问题描述
L小f和P小z的周年纪念日快到啦!为了个L小f一个惊喜,P小z决定去超市买一些礼物
P小z去的超市共贩卖N种不同的物品,每种物品有三种属性,物品的价格 ,L小f的喜欢程度 ,物品的玄学程度 。
这家超市有以下三条奇怪的规矩:
1.每件商品只能购买一次
2.对于每位客人,随机一件商品,这位客人不能购买这件商品
3.物品的玄学值是个玄学,没有任何用处。
现在,P小z有M为客人的购物记录,但是记录残缺不全,只有这些客人进店时带的钱数和被禁止购买的商品的编号。P小z想知道,对于每位客人,最优方案中让L小f的喜欢程度最大的值是多少?
输入格式
输出格式
样例输入
样例输出
数据范围
题解
这题01背包应该很明显吧。。。
关键是01背包求的是前i件物品的最大价值(即喜欢程度),要怎么得到前i件物品中有一件不能选的最大价值。
假设第p件物品不能选,以p为分界点,把n件物品分成两个区间,那么我们要求的就是前1->p-1件物品和后p+1->n件物品的最大价值。而[1,p-1],[p+1,n]这两段区间是连续的,这样就可以用01背包了。
从1->n,n->1分别做一次01背包,设f[i][j]表示前i件物品总价格不超过j的最大喜欢程度,g[i][j]表示i+1->n件物品总价格不超过j的最大喜欢程度,则不选第p件物品的最大喜欢程度为max(f[p-1][j]+g[p+1][m-j]) (m为客人带的钱数,0<=j<=m)
1 #include <cstdio> 2 int n,Q,w[1005],c[1005],a[1005],m[300005],p[300005]; 3 int f[1005][1005],g[1005][1005],V,ans; 4 int max(int x,int y) 5 { 6 return x>y?x:y; 7 } 8 int main() 9 { 10 int i,j,k; 11 scanf("%d",&n); 12 for (i=1;i<=n;i++) 13 scanf("%d%d%d",&w[i],&c[i],&a[i]); 14 scanf("%d",&Q); 15 for (i=1;i<=Q;i++) 16 { 17 scanf("%d%d",&p[i],&m[i]); 18 p[i]++; 19 if (m[i]>V) V=m[i]; 20 } 21 for (i=1;i<=n;i++) 22 for (j=0;j<=V;j++) 23 { 24 f[i][j]=f[i-1][j]; 25 if (j>=w[i]) f[i][j]=max(f[i][j],f[i-1][j-w[i]]+c[i]); 26 } 27 for (i=n;i>=1;i--) 28 for (j=0;j<=V;j++) 29 { 30 g[i][j]=g[i+1][j]; 31 if (j>=w[i]) g[i][j]=max(g[i][j],g[i+1][j-w[i]]+c[i]); 32 } 33 for (i=1;i<=Q;i++) 34 { 35 for (ans=0,j=0;j<=m[i];j++) 36 ans=max(ans,f[p[i]-1][j]+g[p[i]+1][m[i]-j]); 37 printf("%d ",ans); 38 } 39 return 0; 40 }