超大背包
前提:01背包问题是NP难问题,解空间可以用子集树表示。
注意点:
1.剪枝条件。一是如果装入后重量超出背包重量就剪枝。二是如果不装入,剩余背包体积可装入价值的上界加上当前价值cv也达不到当前最优价值bestv也剪枝。
2.要求剩余背包可装入体积的上界,需要排序,然后依次装入物品,直到装不下的时候装入一部分。因此可以一开始就对所有物品按照价值重量比进行排序,这样之后的上界计算依次选择即可。
特别注意:
题目的物品体积和价值可以达到,试想极端情况下80个物品的和是会超出int的,因此必须用long long。调了一晚上bug,必须记住!
#include<iostream>
#include<algorithm>
using namespace std;
long long cw;//当前重量
long long cv;//当前价值
long long bestv;//当前最优价值
int n;//物品数
long long v;//背包总重量
struct Good{
long long value;
long long weight;
bool operator < (const Good &a) const{
return double(value)/double(weight)>double(a.value)/double(a.weight);
}
};
Good good[81];
double Bound(int t)//不选择该物品后,如果当前剩余的所有物品装入(完全背包方式)都无法达到当前的bestv,则剪枝
{
long long leftw = v - cw;
double b = cv;//当前价值
while(t<=n && good[t].weight<=leftw){
leftw = leftw - good[t].weight;
b += good[t].value;
t++;
}
if(t<=n) b+= double(leftw)/double(good[t].weight)*double(good[t].value);//t<=n 说明背包不够了,为了计算上界要装入一部分
return b;
}
void dfs(int t)
{
if(t>n){
if(cv>bestv) bestv=cv;
return;
}
if(cw+good[t].weight<=v){//如果装入就超过背包重量了剪枝。可以装入,进入左子树。
cw += good[t].weight;
cv += good[t].value;
dfs(t+1);
cv -= good[t].value;
cw -= good[t].weight;
}
if(Bound(t+1)>double(bestv)) //不装入,进入右子树。这里其实不剪枝也能AC
dfs(t+1);
}
int main(void)
{
while(cin>>n>>v){
cw=cv=bestv=0;
for(int i=1;i<=n;i++)
cin>>good[i].weight>>good[i].value;
sort(good+1,good+n+1);//排序后顺序选择
dfs(1);
cout<<bestv<<endl;
}
return 0;
}
可以同时参考的链接:https://blog.csdn.net/qq_24489717/article/details/49950027