http://poj.org/gotoproblem?pid=1252
(1)不是单纯的01背包问题,硬币有去有回(即有正有负),这使得用想买你的解法,上限难以确定,所以我开了dp[10000]的数组,还未得到好的优化和解释;
(2)对比两种写法:
1)
for(i=1;i<=6;i++) for(j=a[i];j<=N;j++) dp[j]=min(dp[j], dp[j-a[i]]+1); for(i=1;i<=6;i++) for(j=N-a[i];j>=0;j--) dp[j]=min(dp[j], dp[j+a[i]]+1);
2)
for(i=1;i<=6;i++) { for(j=a[i];j<=N;j++) dp[j]=min(dp[j], dp[j-a[i]]+1); for(j=N-a[i];j>=0;j--) dp[j]=min(dp[j], dp[j+a[i]]+1); }
后一种解法是错误的。其实想一想,背包装的都是“正值”,没见过正负混合装的背包,这里所谓的有正有负,其实本质上是两个背包同时起作用的结果,第二个背包的想过直接叠加在第一个上了。
具体代码:
View Code
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int N=10000; const int Inf=1<<29; int a[10]; int dp[N+1]; int main() { int i, j, k, t; while(scanf("%d", &t)!=EOF) { while(t--) { for(i=1;i<=6;i++) scanf("%d", &a[i]); for(i=1;i<=N;i++) dp[i]=Inf; dp[0]=0; for(i=1;i<=6;i++) for(j=a[i];j<=N;j++) dp[j]=min(dp[j], dp[j-a[i]]+1); for(i=1;i<=6;i++) for(j=N-a[i];j>=0;j--) dp[j]=min(dp[j], dp[j+a[i]]+1); int sum=0, Max=-1; for(i=1;i<=100;i++) { sum+=dp[i]; if(Max<dp[i]) Max=dp[i]; } printf("%.2f %d\n", sum/100.0, Max); } } return 0; }
当然,有分别处理两个背包,再由两者组合,查找出最优值,稍微麻烦一些。
具体代码:
View Code
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int N=100000; const int Inf=1<<29; int a[10]; int dp[N+1]; int main() { int i, j, k, t; while(scanf("%d", &t)!=EOF) { while(t--) { for(i=1;i<=6;i++) scanf("%d", &a[i]); for(i=1;i<=N;i++) dp[i]=Inf; dp[0]=0; for(i=1;i<=6;i++) for(j=a[i];j<=N;j++) dp[j]=min(dp[j], dp[j-a[i]]+1); for(i=1;i<=6;i++) for(j=N-a[i];j>=0;j--) dp[j]=min(dp[j], dp[j+a[i]]+1); int sum=0, Max=-1; for(i=1;i<=100;i++) { sum+=dp[i]; if(Max<dp[i]) Max=dp[i]; } printf("%.2f %d\n", sum/100.0, Max); } } return 0; }
