一. 原题链接: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; } }