背包dp
多重背包转01背包
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 using namespace std; 6 7 const int MAXN=1010; 8 9 int n; 10 struct Node 11 { 12 int w,v; //价钱、价值 13 int id; //玩偶编号 14 }p[MAXN*100]; 15 int dp1[MAXN*100][MAXN]; //正向考虑到第i个物品,花掉j钱时获得的价值为dp1[] 16 int dp2[MAXN*100][MAXN]; //反向考虑到第i个物品,花掉j钱时获得的价值为dp2[] 17 18 int main() 19 { 20 scanf("%d",&n); 21 int cnt=0; //二进制拆分后的玩偶个数 22 for (int i=1;i<=n;i++) 23 { 24 int a,b,c; //价钱、价值、限购次数 25 scanf("%d%d%d",&a,&b,&c); 26 //对每个玩偶二进制拆分 27 int bit=1; 28 while (c>=bit) 29 { 30 cnt++; 31 p[cnt].w=bit*a; 32 p[cnt].v=bit*b; 33 p[cnt].id=i; 34 c-=bit; 35 bit*=2; 36 } 37 if (c) 38 { 39 cnt++; 40 p[cnt].w=c*a; 41 p[cnt].v=c*b; 42 p[cnt].id=i; 43 } 44 } 45 46 memset(dp1,0,sizeof(dp1)); 47 memset(dp2,0,sizeof(dp2)); 48 //正向考虑 49 for (int i=1;i<=cnt;i++) //枚举每份玩偶 50 { 51 for (int j=0;j<1000;j++) dp1[i][j]=dp1[i-1][j]; 52 for (int j=1000;j>=p[i].w;j--) //枚举所花价钱 53 { 54 dp1[i][j]=max(dp1[i][j],dp1[i-1][j-p[i].w]+p[i].v); 55 } 56 } 57 //反向考虑 58 for (int i=cnt;i>=1;i--) 59 { 60 for (int j=0;j<1000;j++) dp2[i][j]=dp2[i+1][j]; 61 for (int j=1000;j>=p[i].w;j--) 62 { 63 dp2[i][j]=max(dp2[i][j],dp2[i+1][j-p[i].w]+p[i].v); 64 } 65 } 66 67 int q; 68 scanf("%d",&q); 69 while (q--) 70 { 71 int d,e; 72 scanf("%d%d",&d,&e); 73 d++; 74 int ans=0; 75 int l=0,r=0; 76 while (p[l+1].id<d && l<n) l++; 77 r=l; 78 while (p[r].id<=d && r<n) r++; 79 for (int j=0;j<=e;j++) //枚举分给左边多少钱数 80 { 81 ans=max(ans,dp1[l][j]+dp2[r][e-j]); //左右合并考虑 82 } 83 printf("%d\n",ans); 84 } 85 86 return 0; 87 }