uva 674
地址:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=615
题意:有1,5,10,25,50这五种硬币。给一个价值,求有多少种组合可以得到该价值。
mark:完全背包。
代码:
最近学习一些大牛设计状态的思路,首先想到了用dp[i][0]代表体积为i最多的价值,dp[i][1]代表体积为i最多的方法。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <iostream> #include <algorithm> #include <map> #define LL long long using namespace std; const int M = 8000; int n; int dp[M][2]; int v[5] = {1, 5, 10, 25, 50}; int main() { int i,j,k; while(~scanf("%d", &n)) { memset(dp, 0, sizeof(dp)); dp[0][1] = 1; for(i = 0; i < 5; i++) { for(j = v[i]; j <= n; j++) { if(dp[j-v[i]][0]+v[i] > dp[j][0]) { dp[j][0] = dp[j-v[i]][0]+v[i]; dp[j][1] = dp[j-v[i]][1]; } else if(dp[j-v[i]][0]+v[i] == dp[j][0]) { dp[j][1] += dp[j-v[i]][1]; } } } printf("%d\n", dp[n][1]); } return 0; }
但是!这里面有无用状态,可以优化,就是dp[i][0],因为本题的体积和价值是一样的,所以上面的转换过程中dp[j-v[i]][0]+v[i] ≡ dp[j][0],也就是说dp[i][0]这个状态是无用状态,即dp[i][0] ≡ i,故代码可优化。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <iostream> #include <algorithm> #include <map> #define LL long long using namespace std; const int M = 8000; int n; int dp[M]; int v[5] = {1, 5, 10, 25, 50}; int main() { int i,j,k; while(~scanf("%d", &n)) { memset(dp, 0, sizeof(dp)); dp[0] = 1; for(i = 0; i < 5; i++) for(j = v[i]; j <= n; j++) dp[j] += dp[j-v[i]]; printf("%d\n", dp[n]); } return 0; }