ZOJ 3631 Watashi's BG

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

二. 题意:求最大报销额。

三. 解题过程:乍一看,明显背包问题。好像数据规模有点大,不管,试试再说。然后TLE了。

上网搜一下,DFS加剪枝。你坑爹的枚举怎么有我动态规划快!!!然后事实告诉我们不能死读书。

每次有选择不选择2种状态:拿或者不拿

剪枝:

1、判断拿起来会不会超过最大值M。

2、判断背包数会不会超出N。

3、如果每天报销额加起来小于等于最大值M。直接都不用搜索了。

4、最重要的剪枝:如果当前的价值 + 剩下所有价值 <= M,直接剪枝。 

四、优化:先降序排序。你升序也行,不过你要从后面开始搜。为什么要降序排序呢,那是因为最后那个最重要的剪枝,排序后,大的都在前面,那么如果要出现满足第四个剪枝的情况的递归层数也就小了。PS:没优化 1180ms 优化后0ms。

五、代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

int weight[31], ans, N, M, IdOfBag, curValue;

void dfs(int id, int value)
{
    ans = ans > value? ans : value;

    if(ans == M)
        return;

    if(id == N)
        return;

    int tempSum = 0, i;
    for(i = id; i < N; i++){
        tempSum += weight[i];
    }

    if(tempSum + value <= M){
        value += tempSum;
        ans = ans > value? ans : value;
        return;
    }

    if(value + weight[id] <= M){
        dfs(id + 1, value + weight[id]);
        dfs(id + 1, value);
    }
    else{
        dfs(id + 1, value);
    }
}

bool cmp(int a, int b)
{
    return a > b;
}

int main()
{
    //freopen("in.txt", "r", stdin);

    int i , j;

    while(cin>>N>>M){
        ans = 0;

        for(i = 0; i < N; i++){
            cin>>weight[i];
            ans += weight[i];
        }

        if(ans <= M){
            cout<<ans<<endl;
            continue;
        }

        ans = 0;
        IdOfBag = 0;
        curValue = 0;

        sort(weight, weight + N, cmp);
        dfs(IdOfBag, curValue);

        cout<<ans<<endl;
    }
}


你可能感兴趣的:(ZOJ 3631 Watashi's BG)