HDOJ 2546 饭卡 解题报告
很有趣的一道题。简单分析一下可知:
(1)如果所有的菜的总金额sum小于等于卡上金额value-5,我们可以购买所有的菜,并且最终余额是value-sum。
(2)如果所有的菜,除去最贵的菜,的金额sum-max小于等于value-5,我们可以先购买其他的菜,最终卡上金额必大于等于5,最后购买那道最贵的菜,使总金额最低,并且最终余额也是是value-sum,可与(1)条件合并。
(3)如果卡上金额小于5,啥也买不了,直接输出吧。
(4)如果都不符合,那就进入最复杂的处理了。先购买适量的菜,使卡内余额的金额大于等于且最接近5,最后购买最贵的菜就好了。子问题也就是01背包问题。
额,还是看代码吧。
#include <iostream> using namespace std; const int MAX=1010; int dp[MAX]; int v[MAX]; int main() { int i,j,n,max,sum,pos,money,temp; while(cin>>n && n) { for(sum=max=i=0;i<n;i++) { cin>>v[i]; sum+=v[i]; if(max<v[i]) max=v[pos=i]; } cin>>money; if(money<5) cout<<money<<endl; else if(sum-max<=money-5) cout<<money-sum<<endl; else { memset(dp,0,sizeof(dp)); if(pos!=n-1) { temp=v[pos]; v[pos]=v[n-1]; v[n-1]=temp; } //仅交换最大值到最后一位,比排序快吧 for(i=0;i<n-1;i++) for(j=money-5;j>=v[i];j--) dp[j]=dp[j]>dp[j-v[i]]+v[i]?dp[j]:dp[j-v[i]]+v[i]; //01背包问题 cout<<money-dp[money-5]-max<<endl; } } }
额,自我感觉代码过是过了,不够完美。网上搜到的一份代码如下:
#include<stdio.h> #include<algorithm> using namespace std; int a[1050],dp[1050]; int main() { int n,m,max,i,j; while(scanf("%d",&n),n) { for(i=0;i<n;i++) scanf("%d",&a[i]); sort(a,a+n); scanf("%d",&m); memset(dp,0,sizeof(dp)); dp[0]=1; max=0; for(i=0;i<n;i++) for(j=m-5;j>=0;j--) if(dp[j]) { dp[j+a[i]]=1; if(j+a[i]>max) max=j+a[i]; } printf("%d\n",m-max); } return 0; }
他的动态规划写的比我漂亮,但是不是所有情况都要这样处理。测试中两份代码都AC,时间都是15MS。
结合两份代码,可以写出来更好的代码了。。。第二份代码中dp数组只有标记功能,可以不用int类型,char就够了。如果想更省一点,char可以分成8份用。。。
做ACM的人可能都有这样的思想,极致节约的时间,空间和代码量。这也是我追求的美学。
没事又综合了一下,如下代码,亦AC了:
#include <iostream> #include <algorithm> using namespace std; const int MAX=1010; char dp[MAX]; int v[MAX]; int main() { int i,j,n,max,sum,pos,money,temp; while(cin>>n && n) { for(sum=max=i=0;i<n;i++) { cin>>v[i]; sum+=v[i]; if(max<v[i]) max=v[pos=i]; } cin>>money; if(money<5) cout<<money<<endl; else if(sum-max<=money-5) cout<<money-sum<<endl; else { memset(dp,0,sizeof(dp)); dp[0]=1; if(pos!=n-1) { temp=v[pos]; v[pos]=v[n-1]; v[n-1]=temp; } for(i=0;i<n;i++) for(j=money-5;j>=0;j--) if(dp[j]) { if(max<j+v[i]) { max=j+v[i]; if(i==n-1) break; } dp[j+v[i]]=1; } cout<<money-max<<endl; } } }