一堆由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;
}
法五:母函数法