关闭

POJ 3181 Dollar Dayz

76人阅读 评论(0) 收藏 举报
分类:

这里写图片描述

题意:输入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][n]) {
        cout << b[k][n];
    }
    cout << a[k][n] << 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][n]) {
        cout << b[k][n];
    }
    cout << a[k][n] << endl;
    return 0;
}

这里写图片描述

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:36390次
    • 积分:759
    • 等级:
    • 排名:千里之外
    • 原创:28篇
    • 转载:75篇
    • 译文:0篇
    • 评论:2条
    文章分类
    最新评论