andre_joy

导航

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;
}

posted on 2012-09-21 17:04  andre_joy  阅读(501)  评论(0编辑  收藏  举报