有数量不限的硬币,币值为25分、10分、5分和1分,请编写代码计算n分有几种表示法。
给定一个int n,请返回n分有几种表示法。保证n小于等于100000,为了防止溢出,请将答案Mod 1000000007。
测试样例:
6
返回:2
暴力方法:
void helper(int n,int res,int& count,int a[])
{
if(n==3)
{
if(res%a[n])
return;
count=(count+1)%1000000007;
return;
}
int k=res/a[n];
for(int i=0;i<=k;i++)
helper(n+1,res-i*a[n],count,a);
}
class Coins
{
public:
int countWays(int n)
{
// write code here
int a[4]={1,5,10,25};
int count=0;
helper(0,n,count,a);
return count;
}
};
动态规划1:
//设n=x1*1+x2*5+x3*10+x4*25 x1,x2,x3,x4>=0且为整数
//当x1,x2,x3,x4取不同的值时对应不同的表示方法
//对于x4而言它的取值范围为[0,n/25],它的每一种取值,表现出了
//一类表示方法,假设用dp[i][j]表示用i种硬币表示j分的硬币,当先确定
//最后一个硬币取得数量时,假设取k个,则上述状态的一个子状态为dp[i-1][j-k*b[i]]
//b[i]为第i种硬币的币值,k的不同取值对应了不同的子状态,将这些子状态加在一起就为最终状态
class Coins
{
public:
int countWays(int n)
{
// write code here
int a[4]={1,5,10,25};
vector<vector<int> >dp(5,vector<int>(n+1,0));
for(int j=0;j<=n;j++)
{
if(j==0)
dp[0][j]=1;
else
{
dp[0][j]=0;
}
}
for(int j=1;j<=4;j++)
{
dp[j][0]=1;
}
for(int i=1;i<=4;i++)
{
for(int j=1;j<=n;j++)
{
for(int k=0;k<=j/a[i-1];k++)
{
dp[i][j]=dp[i][j]%1000000007+dp[i-1][j-k*a[i-1]]%1000000007;
}
}
}
return dp[4][n];
}
};
此时复杂度很高
动态规划2:
class Coins
{
public:
int countWays(int n)
{
// write code here
int a[4] = { 1, 5, 10, 25 };
vector<vector<int> >dp(5, vector<int>(n + 1, 0));
for (int j = 0; j <= n; j++)
{
if (j == 0)
dp[0][j] = 1;
else
{
dp[0][j] = 0;
}
}
for (int j = 1; j <= 4; j++)
{
dp[j][0] = 1;
}
for (int i = 1; i <= 4; i++)
{
for (int j = 1; j <= n; j++)
{
if (j >= a[i - 1])
dp[i][j] = (dp[i - 1][j] % 1000000007 + dp[i][j - a[i - 1]] % 1000000007) % 1000000007;
else
dp[i][j] = dp[i - 1][j];
}
}
return dp[4][n];
}
};
也可以
class Coins {
public:
int countWays(int n) {
// write code here
int coins[4]={1,5,10,25};
int dp[100001] = {0};
dp[0] = 1;
for(int i = 0;i < 4;++i){
for(int j = coins[i];j <= n;++j){
dp[j] =(dp[j]+dp[j-coins[i]])%1000000007;
}
}
return dp[n];
}
};