一堆由1分、2分、5分组成的n个硬币总面值为m分,求一共有多少种可能的组合方式(某种面值的硬币可以数量可以为0)。
法一:
枚举各个面值的硬币数量,如果加起来总个数为n且面值为m,则结果+1。时间复杂度为O(n^3)。
#include<stdio.h> int main() { int n,m,t,i,j,k,ans; scanf("%d",&t); while(t--) { ans=0; scanf("%d%d",&n,&m); for(i=0;i<=n;++i) for(j=0;j<=n;++j) for(k=0;k<=n;++k) if((i+2*j+5*k)==m&&(i+j+k)==n) ++ans; printf("%d\n",ans); } return 0; }
法二:
由于硬币的总个数是一定的,因此第三种面值的硬币数量可以由前两种硬币的数量推出。
故只需枚举前两种硬币的数量,进而推出第三种硬币的数量,再判断面值是否等于m即可。
时间复杂度为O(n^2)。
#include<stdio.h> int main() { int n,m,t,i,j,k,ans; scanf("%d",&t); while(t--) { ans=0; scanf("%d%d",&n,&m); for(i=0;i<=n;++i) for(j=0;j<=n;++j) { k=n-i-j; //注意k可能小于0 if(k>=0&&i+2*j+5*k==m) ++ans; } printf("%d\n",ans); } return 0; }
法三:
考虑如果只有面值为1、2的硬币n枚。那么能够唯一组成区间[n,2n]范围里的任意面值。
于是枚举面值为5的硬币数量,看剩下的面值是否在剩下硬币数量所构成的面值区间内。
时间复杂度为O(m)。
#include<stdio.h> int main() { int n,m,t,i,j,k,ans; scanf("%d",&t); while(t--) { ans=0; scanf("%d%d",&n,&m); for(i=0;i<=m/5;++i) //枚举面值为5的硬币数量 { j=n-i; //剩下的硬币数量 k=m-5*i; //剩下的面值 if(j<=k&&k<=2*j) ++ans; } printf("%d\n",ans); } return 0; }
注意:这里只能枚举面值为5的硬币数量,而不能枚举面值为1或2的硬币数量。因为面值为1、5或者2、5的硬币无法构成区间[n,5n]或[2n,5n]的任意值。
法四:
设a、b、c分别为1、2、5分硬币的数量。则有a+b+c=n,a+2b+5c=m。
由上式可得:a=2n-m+3c>=0,b=m-n-4c>=0。
于是(m-2n)/3<=c<=(m-n)/4
所求结果即为(m-n)/4-(m-2n)/3+1
#include<stdio.h> int main() { int Max,Min,m,n,t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); if(m>=n) Max=(m-n)/4; else {puts("0");continue;} if(m-2*n>=0) { if((m-2*n)%3==0) Min=(m-2*n)/3; else Min=(m-2*n)/3+1; } else Min=0; printf("%d\n",Max-Min+1); } return 0; }
法五:母函数法