ACDREAM 05E 哗啦啦族的01背包问题
Problem Description
背包背包!
唐老师非常开心的在给小彭玉讲背包问题,“01背包就是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2……Wn,与之相对应的价值为P1,P2……Pn。求出获得最大价值的方案。”
在讲完这句话,唐老师就给小彭玉出了道01背包的课后习题,但是小彭玉不会做,那么就只能给你做了~
“有N个物品,你的背包空间为W,每个物品的体积和价值都是W1,W2……Wn。求最大能获得多大价值?”
Input
输入第一行有两个整数N,W。 1<=N<=40,0<=W<=100000000。
接下来一行有N个数,表示物品的体积和价值,W[i]<=100000000。
Output
输出一个整数,表示我们能够获得的最大价值。
Sample Input
4 10
4 3 5 11
Sample Output
9
题目大意:一个价值很大的01背包问题。
解题思路:其实并不是01背包问题。是DFS,但是要折半。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;
typedef long long ll;
int n, w, R, L;
int vis[50];
ll W[50], ans, aL[1<<20], aR[1<<20];
void DFS() {
int pos;
ll temp;
int cnt1 = 0;
for (int i = 0; i < (1<<L); i++) {
temp = 0;
for (int j = 0; j < L; j++) {
if (i & (1 << j)) {
temp += W[j];
}
}
if (temp <= w) {
aL[cnt1++] = temp;
// printf("%lld ", aL[cnt1 - 1]);
}
}
// puts("");
int cnt2 = 0;
for (int i = 0; i < (1 << R); i++) {
temp = 0;
for (int j = 0; j < R; j++) {
if (i & (1 << j)) {
temp += W[L + j];
}
}
if (temp <= w) {
aR[cnt2++] = temp;
// printf("%lld ", aR[cnt2 - 1]);
}
}
sort(aR, aR + cnt2);
for (int i = 0; i < cnt1; i++) {
if (aL[i] == w) {
ans = w;
return;
}
ll sub = w - aL[i];
int rec = upper_bound(aR, aR + cnt2, sub) - aR - 1;
// if (aL[i] == 7) printf("??%lld %lld!!!\n", sub, aR[rec]);
if (aL[i] + aR[rec] > ans && aL[i] + aR[rec] <= w) {
ans = aL[i] + aR[rec];
}
}
}
int main() {
while (scanf("%d %d", &n, &w) == 2) {
memset(aL, 0, sizeof(aL));
memset(aR, 0, sizeof(aR));
ans = 0;
ll temp = 0;
for (int i = 0; i < n; i++) {
scanf("%lld", &W[i]);
temp += W[i];
}
if (temp <= w) {
printf("%lld\n", temp);
continue;
}
L = n / 2;
R = n - n / 2;
DFS();
printf("%lld\n", ans);
}
return 0;
}