饭卡(01背包问题)

网上分析:ios

       设余额为m,令s=m-5,那么咱们就要找使得容量为s的背包最后剩的空间最小的方法,找到以后再用这个剩余容量+5-最大的那个没有被选的商品价值就是最小余额.spa

可是如今咱们不知道最后须要减的那个物品应该是哪一个,能够证实最后须要减的那个物品必定是价值最大的那个.证实:设计

假设价值最大的为max,且咱们假设存在最优的状况(使余额最小)下max物品不是最后一个被减的,最后一个被减的商品价值为mid,假设此时的余额为x.那么仔细想一想若是咱们把max和mid的位置互换,依然能够获得余额为x.(仔细想一想是否是)code

 

我的心得:这么经典简单的背包问题都懵逼了,真的是没谁了。不过确实脑瓜子不够机灵,你想呀,直接DP的花边界难肯定还有负数,这样把5单独拿出来,blog

就能够彻底转化为背包问题了,其实一开始拿出来后我仍是很懵逼的,后面转念一想,拿出来后装最大值而后相减不就剩下的最小余额了吗,真的是一道好题。ip

真的是水得不行。ci

电子科大本部食堂的饭卡有一种很诡异的设计,即在购买以前判断余额。若是购买一个商品以前,卡上的剩余金额大于或等于5元,就必定能够购买成功(即便购买后卡上余额为负),不然没法购买(即便金额足够)。因此你们都但愿尽可能使卡上的余额最少。 
某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可以使卡上的余额为多少。 

Input多组数据。对于每组数据: 
第一行为正整数n,表示菜的数量。n<=1000。 
第二行包括n个正整数,表示每种菜的价格。价格不超过50。 
第三行包括一个正整数m,表示卡上的余额。m<=1000。 

n=0表示数据结束。 
Output对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。Sample Inputstring

1
50
5
10
1 2 3 2 1 1 2 3 2 1
50
0

Sample Outputit

-45
32
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<iomanip>
 6 #include<algorithm>
 7 using namespace std;
 8 const int maxn=1005;
 9 int n,sum;
10 int cai[1005];
11 bool cmp(int a,int b)
12 {
13     return a>b;
14 }
15 int ways[1005];
16 int main()
17 {
18     while(cin>>n&&n!=0){
19            for(int i=1;i<=n;i++)
20                cin>>cai[i];
21                cin>>sum;
22                sort(cai+1,cai+n+1);
23                if(sum<5)
24                 cout<<sum<<endl;
25                else {
26                int ends=5-cai[n];
27                sum=sum-5;
28                memset(ways,0,sizeof(ways));
29                for(int i=1;i<=n-1;i++)
30                  for(int j=sum;j>=cai[i];j--)
31                      ways[j]=max(ways[j],ways[j-cai[i]]+cai[i]);
32                cout<<sum-ways[sum]+ends<<endl;
33                }
34 
35     }
36     return 0;
37 }
相关文章
相关标签/搜索