题意:给你多组数据,然后给出一个面额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; }