Herbs Gathering
2016 ACM/ICPC Asia Regional QingdaoOnline 1011题
题意:给定背包容量和n个物品每个的价值和重量,求能装的物品的最大价值。
分析:背包问题,但是因为背包的价值和重量都在=达到了10的9次方,无法对重量或者价值进行DP,这个时候只能考虑搜索解决。
以前看背包九讲的时候就曾经提到过这个问题,对于一个背包问题,根据数据范围便可以猜测命题者的意图,如果v,w达到了上百万就无法进行DP求解,只可惜当时看的时候没有放在心上,且自己本来就是个蒟蒻,所以网络赛的时候直接就悲剧了,无尽的TLE….
原文:
1、《背包问题九讲》的本意是将背包问题作为动态规划问题中的一类进行讲解。但鉴于的确有一些背包问题只能用搜索来解,所以这里也对用搜索解背包问题做简单介绍。
对于01背包问题,简单的深搜的复杂度是o(2^n)。就是枚举出所有2N种将物品放入背包的方案,然后找最优解。
2、搜索的剪枝基本的剪枝方法不外乎可行性剪枝或最优性剪枝。可行性剪枝即判断按照当前的搜索路径搜下去能否找到一个可行解,例如:若将剩下所有物品都放入背包仍然无法将背包充满(设题目要求必须将背包充满),则剪枝。最优性剪枝即判断按照当前的搜索路径搜下去能否找到一个最优解,例如:若加上剩下所有物品的权值也无法得到比当前得到的最优解更优的解,则剪枝。
3、搜索的顺序在搜索中,可以认为顺序靠前的物品会被优先考虑。所以利用贪心的思想,将更有可能出现在结果中的物品的顺序提前,可以较快地得出贪心地较优解,更有利于最优性剪枝。所以,可以考虑将按照“性价比”(权值/费用)来排列搜索顺序。另一方面,若将费用较大的物品排列在前面,可以较快地填满背包,有利于可行性剪枝。最后一种可以考虑的方案是:在开始搜索前将输入文件中给定的物品的顺序随机打乱。这样可以避免命题人故意设置的陷阱。以上三种决定搜索顺序的方法很难说哪种更好,事实上每种方法都有适用的题目和数据,也有可能将它们在某种程度上混合使用。
4、搜索还是DP? 在看到一道背包问题时,应该用搜索还是动态规划呢?首先,可以从数据范围中得到命题人意图的线索。如果一个背包问题可以用DP解,V一定不能很大,否则o(V N)的算法无法承受,而一般的搜索解法都是仅与N有关,与V无关的。所以,V很大时(例如上百万),命题人的意图就应该是考察搜索。另一方面,N较大时(例如上百),命题人的意图就很有可能是考察动态规划了。另外,当想不出合适的动态规划算法时,就只能用搜索了。例如看到一个从未见过的背包中物品的限制条件,无法想出DP的方程,只好写搜索以谋求一定的分数了。
与上面所说的完全一样,直接利用其思想便可以解决这题了。
首先按性价比排序,直接把不能选的去掉,之后搜索的时候每一步便利用最优性剪枝,取得最大值就行了。
#include
#include
#include
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
struct herb{
LL w, v;
double r;
}h[105];
inline int cmp(herb x, herb y) {return x.r > y.r;}
LL W, ans;
int n, k;
int check(int i, LL sw, LL sv)
{
for (int j = i; j < k && sw < W; j++){
if (h[j].w+sw <= W) sw += h[j].w, sv += h[j].v;
else sv += h[j].r*(W-sw), sw = W;
}
return sv > ans;
}
void solve(int i, LL sw, LL sv)
{
ans = max(ans, sv);
if (i < k && check(i, sw, sv)){
if (sw+h[i].w <= W) solve(i+1, sw+h[i].w, sv+h[i].v);
solve(i+1, sw, sv);
}
}
int main()
{
while (~scanf("%d %I64d", &n, &W)){
k = ans = 0;
for (int i = 0; i < n; i++){
LL w, v;
scanf("%I64d %I64d", &w, &v);
if (w <= W) h[k++] = (herb){w, v, (v+0.0)/w};
}
sort(h, h+k, cmp);
solve(0, 0, 0);
printf("%I64d\n", ans);
}
return 0;
}