1 50 5 10 1 2 3 2 1 1 2 3 2 1 50 0
-45 32
如何证明呢?设想价格最大的物品用来背包了,当然背包容量是c-5,也就是说最优装法含有价格最大的物品,此时无非两种情况,一种是物品一件不剩,另外一种还有剩余。
为方便说明,设价格最大的物品的价格为val。
当物品一件不剩时:考虑另外一种装法,背包容量是c-5,价格最大的物品不用来背包,那么最优装法的总价格减少val,那价格最大的物品,是用做最后一件购买的,因为此时剩余钱数>=5。这样两种方式最后的剩余钱数都是一样的。
当物品还有剩余时:假设剩余的是q1,q2,q3……qn,并且q1>q2>q3>……>qn.可以肯定这些物品如果继续放入背包,那么背包就要超容量了。因为之前假设是最优装法,剩余的物品自然装不下了,否则最优装法里含有qi。又根据假设,背包里有价格为val的物品,这种情况下最大总价格=背包内的总价格+q1,这个是大于等于c-5的,前面的(剩余的物品自然装不下了)就是说明这个问题。现在用q1替换val,背包内的总价格减少了val-q1,肯定还是小于等于c-5的,这时候选择val购买,最大总价格和之前一种方式一样。但是不要忘了,我用q1替换val的,假设q1+q2<=val,那么完全可以用q1,q2替换val,最后再购买val,此时总价格增大了q2,也就是剩余钱数更小了。
无论哪种情况,价格最大的物品不用来装背包,而是作为最后一件购买,答案不会差于用来装背包的情况。
代码:
#include<cstdio> #include<cstring> #include<iostream> using namespace std; int dp[1010],a[1010]; int main() { int n,c; while(scanf("%d",&n),n){ for(int i=0;i<n;i++) scanf("%d",a+i); scanf("%d",&c); if(c<5) {printf("%d\n",c);continue;} int maxx=0,id; for(int i=0;i<n;i++) if(a[i]>maxx) {maxx=a[i];id=i;} c-=5; memset(dp,0,sizeof dp); for(int i=0;i<n;i++) for(int j=c;j>=a[i];j--){ if(id==i) continue; dp[j]=max(dp[j],dp[j-a[i]]+a[i]); } int ans=c+5-dp[c]-maxx; printf("%d\n",ans); } return 0; }