HDU-2016 Coin Change (母函数 | 多重背包)

题意:给你多组数据,然后给出一个面额n,已知有5种钱币1, 5 ,10 , 25, 50求可以组成n元的可能数 (同时所花费的钱币个数要小于等于100)

思路:从多重背包来理解,即使每个硬币占一个单位空间,有100个空间通过状态转移方程:dp[j][k] += dp[j-v[i]][k-1]; 这里dp记录的便是组合的种类数(相当于递推公式,

从dp[0][0]这个状态开始,尝试放入不同的硬币并且符合条件)

总母函数的角度:同样相当于取5种类型的硬币,然后通过母函数性质模拟多项式乘积 便可以得到

多重背包完整代码:

#include<cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int a[255][105],b[255][105];
int v[6]={0,1,5,10,25,50};
int dp[110][300]; 
int num[255]={0};
int i,j,k,t,n;
int ans ;
void solve(){
    memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(int i=1;i<=5;i++)
            for(int j=1;j<=100;j++)
                for(int k=250;k>=v[i];k--)   
                    dp[j][k]+=dp[j-1][k-v[i]];
}
int main()
{    
    solve();//预处理 
    while(~scanf("%d",&n))
    {
        ans= 0;
        for(int i =0;i<=100;i++)
            ans +=dp[i][n];
        printf("%d
",ans);
    }
    return 0;
}

母函数完整代码:

#include<cstdio>
int a[255][105],b[255][105];
int v[6]={0,1,5,10,25,50};
int num[255]={0};
int i,j,k,t,n;
void solve(){
    a[0][0]=1;
    for(i=1;i<=5;i++)//种类数 
    {
        for(j=0;j<=250;j++)//最大额度 
            for(k=0;j+k*v[i]<=250;k++)
                for(t=0;t+k<=100;t++)//硬币个数限制 
                    b[j+k*v[i]][t+k]+=a[j][t]; 
                    
        for(j=0;j<=250;j++)//赋值与清零 
            for(t=0;t<=100;t++)
            {
                a[j][t]=b[j][t];
                b[j][t]=0;
            }
    }
    for(i=0;i<=250;i++)//将系数相加(即为组合可能数) 
        for(j=0;j<=100;j++)
            num[i]+=a[i][j];    
} 
int main()
{    
    solve();//预处理 
    while(~scanf("%d",&n))
    {
        printf("%d
",num[n]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Tianwell/p/11214082.html