nyoj 1091 还是01背包(超大数dp)

时间:2023-05-01 10:54:20

nyoj 1091 还是01背包

描述

有n个重量和价值分别为 wi 和 vi 的物品,从这些物品中挑选总重量不超过W的物品,求所有挑选方案中价值总和的最大值

1 <= n <=40

1 <= wi <= 10^15

1 <= vi <= 10^15

1 <= W <= 10^15

分析:在做的时候毫无头绪,在网上看了其他大神的博客才AC了,数据超大无法使用之前的思路(超时且dp数组开不了这么大),但是由本题条件可知n的值非常小,可用递归配合剪枝解题

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define Max(a, b) a > b ? a:b
using namespace std;
typedef long long ll;
const ll INF = ;
ll w[], v[];
ll sw[], sv[];
ll n, W, ans;
void solve(int i, ll W, ll V) {
if(i == ) {
ans = Max(ans, V);
return;
}
if(W == || ans >= V + sv[i]) return;//背包满或者当前总的加上这个前i个的总价值小于当前的总value,这步是剪枝
if(W >= sw[i]) {//因为是从上往下找的,所以只要当前容量能装下前i个的和,所以这时一定是最大的 ,剪枝
V += sv[i];
ans = Max(ans, V);
W = ;
return;
}
if(w[i] <= W) solve(i-, W - w[i], V + v[i]);
solve(i-, W, V);
}
int main() {
while(cin >> n >> W) {
ans = -;
memset(sw, , sizeof(sw));
memset(sv, , sizeof(sv));
for(int i = ; i <= n; i++) {
cin >> w[i] >> v[i];
sw[i] = sw[i-] + w[i];
sv[i] = sv[i-] + v[i];
}
solve(n, W, );
cout << ans << endl;
}
return ;
}