饭卡(01背包问题)
网上分析:
设余额为m,令s=m-5,那么我们就要找使得容量为s的背包最后剩的空间最小的方法,找到之后再用这个剩余容量+5-最大的那个没有被选的商品价值就是最小余额.
但是现在我们不知道最后需要减的那个物品应该是哪个,可以证明最后需要减的那个物品一定是价值最大的那个.证明:
假设价值最大的为max,且我们假设存在最优的情况(使余额最小)下max物品不是最后一个被减的,最后一个被减的商品价值为mid,假设此时的余额为x.那么仔细想想如果我们把max和mid的位置互换,依然可以得到余额为x.(仔细想想是不是)
个人心得:这么经典简单的背包问题都懵逼了,真的是没谁了。不过确实脑瓜子不够机灵,你想呀,直接DP的花边界难确定还有负数,这样把5单独拿出来,
就可以完全转化为背包问题了,其实一开始拿出来后我还是很懵逼的,后面转念一想,拿出来后装最大值然后相减不就剩下的最小余额了吗,真的是一道好题。
真的是水得不行。
电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。
某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。
某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。
Input多组数据。对于每组数据:
第一行为正整数n,表示菜的数量。n<=1000。
第二行包括n个正整数,表示每种菜的价格。价格不超过50。
第三行包括一个正整数m,表示卡上的余额。m<=1000。
n=0表示数据结束。
Output对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。Sample Input
1 50 5 10 1 2 3 2 1 1 2 3 2 1 50 0
Sample Output
-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 }