40个物品,容量范围为1e15,物品重范围为1e15
简单dp来写的话为o(1e15*40)
枚举全部取的可能是2^40种,可以折半分为n2,n-n2来枚举。
变成枚举2*2^20种,左边枚举完后按照重量排序,如果大重量的价值小于之前小重量的价值就全部剔除。
那么右边背包枚举全部可能的时候,W-w=所剩重量(w可以是0),可以二分左边背包的所有重量小于剩余重量而
价值又是最大的。
pair的使用
pari<int,int>q1;
pair[1].first=;查找
p1[i]=make_pair(s1,t1);添加
#include <queue>
#include<iostream>
#include<stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <ctime>
using namespace std;
struct ttt{
double x1,y1,x2,y2;
};
typedef long long ll;
ll w[50];
ll v[50];
pair<int,int>q1[1100000];
int main(){
freopen("in.txt","r",stdin);
//freopen("output.txt","w",stdout);
int i,j,k,l,f1,f2,f3,t1,t2,t3,m;
int l1,l2,l3,f4,f5;
int n,sum1;
int tt=0;
int sup,sub;
cin >> n;
for(i=0;i<n;i++)
cin >> w[i];
for(i=0;i<n;i++)
cin >> v[i];
ll W;
cin >> W;
int n2=1<<(n/2);
for(i=0;i<n2;i++){//(2*1)^n 也就是8个状态
ll s1=0,v1=0;
for(j=0;j<n/2;j++)
if(i >> j & 1){ //对这个位置是否有1,也就是这个状态取没取这个物品
s1+=w[j];
v1+=v[j];}
q1[i]=make_pair(s1,v1);
}
sort(q1,q1+n2); //对二进制的运算符不熟悉就这样加括号
ll u=0;
m=0;
for(i=0;i<n2;i++){
if(q1[i].second>u){
q1[m++]=q1[i];
u=q1[i].second;
}
}
int left1,right1,mid1;
ll max1=0;
for(i=n2;i<1<<n;i++){
ll s1=0,v1=0;
for(j=n/2;j<n;j++)
if(i>>j & 1){
s1+=w[j];
v1+=v[j];
}
left1=0;right1=m-1;
int w2=W-s1;
if(w2<0)continue; //不存在比第一个重量还小,因为第一个是0
while(right1>=left1){
mid1=(left1+right1)/2;
if(q1[mid1].first<=w2){ //剩余w2空间
left1=mid1+1;
max1=max(max1,v1+q1[mid1].second);
}else{
right1=mid1-1;
}
}
}
cout << max1 << endl;
return 0;
}