统计硬币
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 8202 Accepted Submission(s): 5606
Problem Description
假设一堆由1分、2分、5分组成的n个硬币总面值为m分,求一共有多少种可能的组合方式(某种面值的硬币可以数量可以为0)。
Input
输入数据第一行有一个正整数T,表示有T组测试数据;
接下来的T行,每行有两个数n,m,n和m的含义同上。
接下来的T行,每行有两个数n,m,n和m的含义同上。
Output
对于每组测试数据,请输出可能的组合方式数;
每组输出占一行。
每组输出占一行。
Sample Input
2
3 5
4 8
Sample Output
1
2
Author
lemon
Source
Recommend
分析:可以用二维的母函数来记录一下数量,也可以用DFS
母函数:
#include<iostream> #include <cstring> using namespace std; #define M 1000 //M为(x的最大指数+1) #define MAXN 130 //MAXN为最大有多少项相乘 int a[M][150],b[M][150];//a[M]中存最终项系数;b[M]中存取中间变量; int main() { int m,n; int i,j,k,r; m=MAXN; int t; scanf("%d",&t); while(t--){ scanf("%d%d",&r,&n); memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); //n为所求的指数的值: "; //因为只求指数为n的系数的值:所以循环只到n就结束 for(i=0;i<=n;i++)//初始化第一个式子:(1+X+X^2+X^3+...) 所以将其系数分别存到a[n] { a[i][i]=1; } for(i=2;i<=5;i=i+3)//从第2项式子一直到第n项式子与原来累乘项的和继续相乘 { for(j=0;j<=n;j++)//从所累乘得到的式子中指数为0遍历到指数为n 分别与第i个多项式的每一项相乘 for(k=0;k+j<=n&&k/i<=r;k+=i)//第i个多项式的指数从0开始,后面的每项指数依次比前面的多i,比如当i=3时,第3项的表达式为(1+x^3+x^6+x^9+……),直到所得指数的值i+j>=n退出 { for(int z=0;z+k/i<=r;z++){ b[j+k][z+k/i]+=a[j][z]; }//比如前面指数为1,系数为3,即a[1]=3 的一项和下一个表达式的指数为k=3的相乘,则得到的式子的系数为,b[j+k]=b[4]+=a[1],又a[1]=3,所以指数为4的系数为b[4]=3; } for(j=0;j<=n;j++)// 然后将中间变量b数组中的值依次赋给数组a,然后将数组b清零,继续接收乘以下一个表达式所得的值 { for(int k=0;k<=r;k++){ a[j][k]=b[j][k]; b[j][k]=0; } } } printf("%d ",a[n][r]); // 指数为n的项的系数为: } return 0; }
DFS:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; int n,m,ans; void dfs(int x,int sum,int step) { if(sum>m)return; if(sum==m&&step==n) { ans++; return; } if(step==n) return; if(x==5) { dfs(5,sum+5,step+1); } else if(x==1) { dfs(1,sum+1,step+1); dfs(2,sum+2,step+1); dfs(5,sum+5,step+1); } else if(x==2) { dfs(2,sum+2,step+1); dfs(5,sum+5,step+1); } } int main() { int t; scanf("%d",&t); while(t--) { ans=0; scanf("%d%d",&n,&m); dfs(1,1,1); dfs(2,2,1); dfs(5,5,1); printf("%d ",ans); } return 0; }