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

1<=n<=40

1<=wi,vi<=10^15

1<=W<=10^15

输入:

4
2 1 3 2
3 2 4 2
5

输出:

7(挑选0,1,3号)

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 10000;
int n;
ll w[MAXN];
ll v[MAXN];
ll W;
pair<ll,ll> ps[1 << (MAXN/2)];



bool cmp(const pair<ll,ll> &a,const pair<ll,ll> &b ){
	if(a.first==b.first)
		return a.second<b.second;
	return a.first<b.first;
} 
int main(){

	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d",&w[i]);
	}
	
	for(int i=0;i<n;i++){
		scanf("%d",&v[i]);
	}
	
	
	
	scanf("%d",&W);
	
	int n2 = n/2;
	
	for(int i=0;i< 1<<n2 ;i++){
		
		ll sw=0; ll sv =0;
		for(int j=0;j<n2;j++){
			if(i>>j &1){
				sw+=w[j];
				sv+=v[j];				
			}	
		}
		ps[i] = make_pair(sw,sv);
	}
	sort(ps,ps+(1<<n2));
	
	int m=1;
	for(int i=1;i<1<<n2;i++){
		if(ps[m-1]<ps[i]){
			ps[m++] = ps[i];
		}
	}
	ll res= 0;
	for(int i=0;i<1<<(n-n2);i++){
		
		ll sw =0; ll sv =0;
		for(int j=0;j<(n-n2);j++){
			if(i>>j &1){
				sw+=w[n2+j];
				sv+=v[n2+j];
			}
		}
		
		if(sw<=W){
			ll tv = (lower_bound(ps,ps+m,make_pair(W-sw,INF),cmp)-1)->second;
			res = max(res,sv+tv);
		}
	}
	printf("%lld\n",res);
	return 0;
}