您的位置:首页 > 其它

UVA 11137 Ingenuous Cubrency(完全背包)

2014-10-23 21:50 357 查看
UVA 11137 Ingenuous Cubrency(完全背包)
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2078
题意:

有21种面值的硬币,面值分别为1,8,27,…9261(21的立方). 即每种硬币的面值都是i的立方值(1<=i<=21)且每种硬币可以无限使用,现在给你一个面值x,问你用以上硬币构成x面值的钱最多有多少种方法?

分析:


本题与之前做的UVA 147和UVA 674基本一样.


我们令val[i]表示第i种硬币的面值, 令dp[i][j]==x 表示由前i种硬币构成面值j美分有x种方式.

初值dp为0且dp[0][0]=1. 状态方程为:

dp[i][j] = sum(
dp[i-1][j] , dp[i][j-val[i]] ) //sum为求和

最终我们所求为dp
[x]的值.

如何理解上述的状态转移方程呢?

首先来看dp[i][j], 它表示用前i中硬币构成j美分的方法数目. 那么:

1. 如果我们根本不用第i种硬币(只用前i-1种硬币即可),我们可以知道有dp[i-1][j]种方式可以(不用任何一个第i种硬币)构成j美分.

2. 如果我们至少用1个第i种硬币来构成j美分, 那么我们可以知道有dp[i][j-val[i]] 种方法能达成目的.

综上所述, dp[i][j]==用前i种硬币构成j美分的方法总数== sum( dp[i-1][j] , dp[i][j-val[i]] ).

程序实现用的滚动数组, 所以dp只有[j]这维. 且注意j必须从小到大循环了.(想想为什么)

注意:本题输出数据超了int,需要用longlong.

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=10000+5;

int n=21;//硬币种类
int val[21+5];//硬币面值
long long dp[maxn];

int main()
{
    //初始化
    for(int i=1;i<=21;i++)
        val[i]= i*i*i;
    memset(dp,0,sizeof(dp));
    dp[0]=1;

    //DP递推
    for(int i=1;i<=n;i++)
        for(int j=val[i];j<maxn;j++)
            dp[j] += dp[j-val[i]];

    //输出结果
    int v;
    while(scanf("%d",&v)==1)
        printf("%lld\n",dp[v]);
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: