(背包问题2)有N(O<N≤50)个物品,第i个物品体积为v[i](0≤v[i]≤10^18),价值为w[i](0≤w[i]≤10^17)。现有一个容量为V(0≤V≤10^18)的背包。你需要选择一些物品使
得体积之和不超过V且价值最大。求出最大价值及方案。如有多种方案,尽可能选择编号较大的方案(即尽量选第n个,仍有多组解选第n-1个,以此类推)。
提示:将物品按标号是否大于n/2分成两组,每组内枚举如何选择。再在两组间确定方案。
试补全程序。
#include <iostream>
using namespace std;
const long long inf=___(1)___;
long long v[41];
long long w[41];
struct Item {
long long value, weight, choose;
} itm[2][1<<20];
bool cmp1(Item a, Item b) {
return a.value < b.value||(a.value == b.value && a.choose < b.choose);
}
bool cmp2(Item a, Item b) {
return a.value < b.value||(a. value == b.value && a.choose==b.choose);
}
int get_id(int n) {
for(int i=0; ; ++i)
if(!(n>>i)) return i-1;
}
void sort(Item item[], int L, int R) {
if(L>= R) return;
int x=rand()%(R-L+1)+L;
swap(item[L], item[x]);
int a=L+1,b= R;
while (a<b) {
while (a<b&& cmp1(item[a], item[L]))
++a;
while(a< b&& ___(2)___)
--b;
swap(item[a],item[b]);
}
while (b<= R&& item[b].value == item[L].value)
++b;
if (item[a].value < item[L].value)
swap(item[a],item[L]);
sort(item, L, a-1);
sort(item, b, R);
}
int solve(int L, int R, Item item[]) {
item[0].value=0;
item[0].choose = 0;
int len = ___(3)___;
for (int i=1; i <= len; ++i) {
int tmp= ___(4)___;
item[i].value = item[i - tmp].value + v[L + get_id(tmp)];
item[i].weight = item[i - tmp].weight + w[L + get_id(tmp)];
if (item[i].value > inf) item[i].value = inf;
item[i].choose = i;
}
sort(item, 0, len);
return len;
}
int main() {
int N;
long long V, ans = 0;
cin>>N>>V;
for (int i = 1; i<= N; ++i)
cin>> v[i] >> w[i];
int len1 = solve(1,N/2, itm[0]);
int len2 = solve(N/2 + 1, N, itm[1]);
for (int i= 1; i<= len2; ++i)
itm[1][i].value=max(itm[1][i].value, itm[1][i-1].value);
long long choose = 0;
for (int i= 0; i<= len1; ++i) {
while (len2 >= 0 && itm[0][i].value + itm[1][len2].value>V)
--len2;
if(len2>=0) {
long long new_value = itm[0][i].weight + itm[1][len2].weight;
long long new_choose = ___(5)___ ;
if (ans == new_value)
choose = max( choose, new_choose);
if (ans < new_value) {
ans = new_value ;
choose = new_choose ;
}
}
}
cout<<ans<<endl;
for (int i= 0; i< N; i++)
if (choose & (1LL<<i))
cout<<i+1<<' ';
cout << endl;
}
选择题
1) ⑴处应填( )。
2) ⑵处应填( )。
3) ⑶处应填( )。
4) ⑷处应填( )。
5) ⑸处应填( )。