Farmer John goes to Dollar Days at The Cow Store and discovers an unlimited number of tools on sale. During his first visit, the tools are selling variously for $1, $2, and $3. Farmer John has exactly $5 to spend. He can buy 5 tools at $1 each or 1 tool at $3 and an additional 1 tool at $2. Of course, there are other combinations for a total of 5 different ways FJ can spend all his money on tools. Here they are:
Input 1 @ US$3 + 1 @ US$2
1 @ US$3 + 2 @ US$1
1 @ US$2 + 3 @ US$1
2 @ US$2 + 1 @ US$1
5 @ US$1Write a program than will compute the number of ways FJ can spend N dollars (1 <= N <= 1000) at The Cow Store for tools on sale with a cost of $1..$K (1 <= K <= 100).A single line with two space-separated integers: N and K.
OutputA single line with a single integer that is the number of unique ways FJ can spend his money.
Sample Input5 3Sample Output
5
题意:输入:n k,用从1~k之间的整数,相加能得出来n,不同式子表示方法有多少种;
第一种理解方式: 最大不超过k的 n划分数 有多少种;
dp[n][k] 为 最大不超的k的 n的划分数的种数;
dp[n][k] = dp[n][k-1] + dp[n-k][k];
分含k和不含k的式子:
dp[n][k-1] 为不包含的k的划分数;
dp[n-k][k] 为包含k的划分数,让n-k的每个划分数后都加个k;
一定要注意初始化时,dp[0][k] ,不超过k的整数,和为0 都赋予 1;第二个代码有解释:
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define Max 1010
long long dp[Max][110],dp1[Max][110]; // dp[i][j] 不超过j 的数组成i的划分数;
//dp 存一个数的后十七位,dp1 存一个数后十七位之前的位数;
int main()
{
int i,j;
int n,k;
long long inf = 1;
for(i = 0;i<18;i++)
inf *= 10;
while(~scanf("%d%d",&n,&k))
{
memset(dp1,0,sizeof(dp1));
for(i = 0;i<=k;i++)
{
dp[0][i] = 1; // 组成0的划分数永远都为1;
}
for(i = 1;i<=n;i++)
{
for(j = 1;j<=k;j++)
{
if(i<j)
{
dp[i][j] = dp[i][j-1];
dp1[i][j] = dp1[i][j-1];
}
else
{
dp1[i][j] = dp1[i][j-1]+dp1[i-j][j]+(dp[i][j-1]+dp[i-j][j])/inf;
dp[i][j] = (dp[i][j-1]+dp[i-j][j])%inf;
}
//dp[i][j-1]; 不包含 j的划分数
//dp[i-j][j]; 包含j 的划分数;
}
}
if(dp1[n][k])
printf("%lld%017lld\n",dp1[n][k],dp[n][k]);
else printf("%lld\n",dp[n][k]);
}
return 0;
} 思路二:
完全背包;
把 k种玩具的价格当做是 有多少种物品, n 为 背包容量;
dp[i][j] 前i种玩具能组成 j 的 划分数;
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
__int64 dp[1110][1110],dp1[1110][1110]; //dp[i][j] 表示为从前i中的玩具中的组成 j 元的方法数;
// dp为后17位,dp1为后17为之前的数;
int main()
{
int n,k,i,j;
while(~scanf("%d%d",&n,&k))
{
memset(dp1,0,sizeof(dp1));
for(i = 0;i<=n;i++)
{ // 初始化很重要
dp[i][0] = 1; // 前i中玩具组成 0 元的全部为 1;为0元素;
} // dp[i][j],当i==j时,dp[i][j] +=dp[i][j-i]
// 0 元素被计数时,就变成了0+j,被计数了;
//所以前i中玩具组成 0 元的全部为 1;
__int64 inf = 1;
for(i = 0;i<18;i++)
{
inf *= 10;
}
/*for(i = 1;i<=k;i++)
{
for(j = 1;j<=n;j++)
{
//dp[i][j] = 0;
dp[i][j] = dp[i-1][j];
for(int t = 1;t*i<=j;t++) //真正的完全背包是这样的,这是耗时的;
{
if(j>=t*i);
dp[i][j] += dp[i-1][j-t*i];
}
}
}*/
for(i = 1;i<=k;i++)
{
for(j = 1;j<=n;j++)
{
if(j<i)
{
dp[i][j] = dp[i-1][j];
dp1[i][j] = dp1[i-1][j]; // 17之前的数,17位之后的数;
}
else
{
dp1[i][j] = (dp1[i-1][j]+dp1[i][j-i])+(dp[i-1][j]+dp[i][j-i])/inf;
dp[i][j] = (dp[i-1][j] + dp[i][j-i])%inf; //dp[i][j-i] 前面所有的情况已经加过了;直接加前面总体的结果就行了;
}
}
}
if(dp1[k][n]!=0)
printf("%I64d%017I64d\n",dp1[k][n],dp[k][n]);
else printf("%I64d\n",dp[k][n]);
}
return 0;
}
本文介绍了一个经典的组合问题:如何计算在有限预算内,购买不同价格工具的所有可能组合数量。通过两种不同的方法——递推和完全背包问题的解决思路,详细阐述了算法实现,并提供了完整的代码示例。
5万+

被折叠的 条评论
为什么被折叠?



