您的位置:首页 > 其它

POJ 3181 Dollar Dayz

2016-05-30 17:07 387 查看


题意:输入n、k,问将n用1~k这k个数字进行拆分,有多少种拆分方法。例如:n=5,k=3则有以下5种拆分方法:

n=3+2

n=3+1+1

n=2+1+1+1

n=2+2+1

n=1+1+1+1+1

此题是个背包问题,如果想不到可以将其看作是一个普通动态规划。

dp[i][j] 表示用i种价格配出金额j的方案数。

状态转移方程:dp[i][j]=dp[i-1][j]+dp[i-1][j-i]+dp[i-1][j-2i]+dp[i-1][j-3j]…+dp[i-1][0]

状态转移方程就是将所有由i-1状态,通过添加k(=0,1,2…)个i可以到达dp[i][j]的状态的数字相加。如:dp[i-1][j]表示由i-1价格不需要添加i就可以到达金额j,dp[i-1][j-i]表示由i-1种价格需要再利用加个i且要添加1个价格i才能到达金额j,dp[i-1][j-2i]表示由i-1种价格需要再利用价格i且要添加2个i才能到达金额j,以此类推。

由于相加后得到的结果可能相当大,已经超过了long long,所以应该用大数。用两个unsigned long long 分别表示低位和高位,由于 unsigned long long 最大范围到
2^64-1
即:18446744073709551615 ;所以取一个比这个值小一个数量级同时又能被10整除的数作为limit。

#include <iostream>
using namespace std;

unsigned long long b[105][1005], a[105][1005];
unsigned long long inf = 1;

int main()
{

int n, k;
cin >> n >> k;
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
for (int i = 0; i < 18; ++i) {
inf *= 10;
}
a[0][0] = 1;
//dp[i][j] = dp[i – 1][j] + dp[i – 1][j – i] + dp[i – 1][j – 2 * i] + … + dp[i – 1][0]
for (int i = 1; i <= k; ++i)
{
for (int j = 0; j <= n; ++j)
{
for (int m = 0; m*i <= j; ++m)
{
b[i][j] = b[i][j] + b[i - 1][j - m*i] + (a[i][j] + a[i - 1][j - m*i]) / inf;
a[i][j] = (a[i][j] + a[i - 1][j - m*i]) % inf;
}
}
}

if (b[k]
) {
cout << b[k]
;
}
cout << a[k]
<< endl;

return 0;
}


提交之后是可以过的,结果如下:



看了大神的分析后,觉得自己的A题之路还有如此的遥远。



仔细考虑可以发现其实可以转到dp[i][j]的状态有两种:一种是dp[i-1][j]就是不用i这个数字拼接j这个数字的方法数,另一种是a[i][j-i]就是用了i这个数字拼接得到j-i的方法数。那么状态转移方程可以写为dp[i][j]=dp[i-1][j]+a[i][j-i]。

#include<iostream>

using namespace std;

long long a[105][1005], b[105][1005];

int main() {
int n, k;
cin >> n >> k;
long long inf = 1;
for (int i = 0; i < 18; ++i) {
inf *= 10;
}
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
for (int i = 0; i <= k; ++i) {
a[i][0] = 1;
}
//dp[i][j]=dp[i-1][j]+dp[i][j-i];
for (int i = 1; i <= k; ++i) {
for (int j = 1; j <= n; ++j) {
if (i > j) {
b[i][j] = b[i - 1][j];
a[i][j] = a[i - 1][j];
continue;
}
a[i][j] = (a[i - 1][j] + a[i][j - i]) % inf;
b[i][j] = b[i - 1][j] + b[i][j - i] + (a[i - 1][j] + a[i][j - i]) / inf;
}
}
if (b[k]
) {
cout << b[k]
;
}
cout << a[k]
<< endl;
return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: