zoj - 3631 - Watashi's BG(dfs)

本文详细介绍了如何通过优化背包问题的算法,从160ms降低到80ms,包括从大到小排序、更新最大报销额、预计算前N项和等关键步骤,并分享了进一步优化到0ms的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:N天钱序列,最大报销额为M,对于其中的一天可选择报不不报,问最多能报销多少钱。(每天的钱不可拆分)(1 <= N <= 30, 0 <= M <= 10000000)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3631

——>>背包呀,不过要优化,寒假时优化到160ms,今天重刷,优化到了80ms,痛快!

优化思想:

1、从大到小排序;

2、到了最大报销额,更新MAX;

3、将后面的加起来,看是否比现在的MAX小;

4、第3步中将后面的加起来,可事先打个前N项和的表。

#include <cstdio>
#include <algorithm>

using namespace std;

const int maxn = 30 + 10;
int N, M, MAX, a[maxn], sum[maxn];

bool cmp(const int& e1, const int& e2)
{
    return e1 > e2;
}
void dp(int cur, int cur_sum)
{
    if(cur_sum == M)
    {
        MAX = cur_sum;
        return;
    }
    if(cur == N+1)
    {
        MAX = max(MAX, cur_sum);
        return;
    }
    if(cur_sum + sum[N] - sum[cur-1] < MAX) return;
    if(cur_sum + a[cur] <= M) dp(cur + 1, cur_sum + a[cur]);
    dp(cur + 1, cur_sum);
}
int main()
{
    int i;
    while(scanf("%d%d", &N, &M) == 2)
    {
        for(i = 1; i <= N; i++) scanf("%d", &a[i]);
        sort(a + 1, a + 1 + N, cmp);
        sum[0] = 0;
        sum[1] = a[1];
        for(i = 2; i <= N; i++) sum[i] = sum[i-1] + a[i];
        MAX = 0;
        dp(1, 0);
        printf("%d\n", MAX);
    }
    return 0;
}

再次优化,0ms过!!!痛快!!!

优化思想5:

增加恰好到达M的标记。

#include <cstdio>
#include <algorithm>

using namespace std;

const int maxn = 30 + 10;
int N, M, MAX, a[maxn], sum[maxn];
bool ok;

bool cmp(const int& e1, const int& e2)
{
    return e1 > e2;
}
void dp(int cur, int cur_sum)
{
    if(ok) return;
    if(cur_sum == M)
    {
        MAX = cur_sum;
        ok = 1;
        return;
    }
    if(cur == N+1)
    {
        MAX = max(MAX, cur_sum);
        return;
    }
    if(cur_sum + sum[N] - sum[cur-1] < MAX) return;
    if(cur_sum + a[cur] <= M) dp(cur + 1, cur_sum + a[cur]);
    dp(cur + 1, cur_sum);
}
int main()
{
    int i;
    while(scanf("%d%d", &N, &M) == 2)
    {
        for(i = 1; i <= N; i++) scanf("%d", &a[i]);
        sort(a + 1, a + 1 + N, cmp);
        sum[0] = 0;
        sum[1] = a[1];
        for(i = 2; i <= N; i++) sum[i] = sum[i-1] + a[i];
        MAX = 0;
        ok = 0;
        dp(1, 0);
        printf("%d\n", MAX);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值