HDU 2546
这是一道01背包的变体。题目加了限制条件,当卡上金额大于等于5元时才能购买成功,我们不妨将这里的5元视为“0“,因为在DP过程中金额不能低于5,所以最后要用到的结果应该是dp[m-5]。既然我们保证了余额一直是大于等于5的,那么最后还能购买一次,所以,我们将最贵的一样菜留在最后,在DP的过程结束之后再购买,这样就能保证最后的余额最少。
开始,我在写这道题的时候由于觉得要剩5元,于是将循环改为了 for i 1 to n
for j m+5 to 5
这样也是可以的,只是要注意最后结果应该使用dp[m],而不是dp[m+5],开始由于使用了dp[m+5],所以WA了。j从m+5到5,也是为了保证不小于5元,但是实际上m to 5就行了,这一点当时没有想清楚,造成了思路上的混乱。这是我思维上的一个弱点,大体方向是正确的,但是在细节上的思考还不够全面、细致,希望今后能够改正。
#include<stdio.h> #include<string.h> #define MAX_LMT 1010 int max(int,int); int main() { int n; while(scanf("%d",&n),n) { int cost[MAX_LMT],i,j,m,dp[MAX_LMT],most_expsv=0,recrd_expsv; for(i=1;i<=n;i++) { scanf("%d",&cost[i]); if(cost[i]>most_expsv) { most_expsv=cost[i]; recrd_expsv=i; } } scanf("%d",&m); if(m<5) { printf("%d\n",m); } else { memset(dp,0,sizeof(dp)); for(i=1;i<=n;i++) { for(j=m+5;j>=5;j--) { if(i!=recrd_expsv&&j>=cost[i]+5) { dp[j]=max(dp[j],dp[j-cost[i]]+cost[i]); } } } printf("%d\n",m-dp[m]-most_expsv);//使用dp[m],因为上面初始的是j+5 } } return 0; } int max(int x,int y) { return x>y?x:y; }
#include<stdio.h> #include<string.h> #define MAX_LMT 1010 int max(int,int); int main() { int n; while(scanf("%d",&n),n) { int cost[MAX_LMT],i,j,m,dp[MAX_LMT],most_expsv=0,recrd_expsv; for(i=1;i<=n;i++) { scanf("%d",&cost[i]); if(cost[i]>most_expsv) { most_expsv=cost[i]; recrd_expsv=i; } } scanf("%d",&m); if(m<5) { printf("%d\n",m); } else { memset(dp,0,sizeof(dp)); for(i=1;i<=n;i++) { for(j=m;j>=0;j--) { if(i!=recrd_expsv&&j>=cost[i]) { dp[j]=max(dp[j],dp[j-cost[i]]+cost[i]); } } } printf("%d\n",m-dp[m-5]-most_expsv); } } return 0; } int max(int x,int y) { return x>y?x:y; }