复杂的整数划分问题

Description

将正整数表示成一系列正整数之和,n=n1+n2+…+nk, 其中n1>=n2>=…>=nk>=1 k>=1 
正整数的这种表示称为正整数的划分。

Input
标准的输入包含若干组测试数据。每组测试数据是一行输入数据,包括两个整数N 和 K。 
(0 < N <= 50, 0 < K <= N)
Output
对于每组测试数据,输出以下三行数据:
第一行: N划分成K个正整数之和的划分数目
第二行: N划分成若干个不同正整数之和的划分数目
第三行: N划分成若干个奇正整数之和的划分数目
Sample Input
5 2
Sample Output
2
3
3
Hint
第一行: 4+1, 3+2,
第二行: 5,4+1,3+2

第三行: 5,1+1+3, 1+1+1+1+1+1

快乐的dp,快乐的我.

一道比较复杂的简单dp,状态转移方程比较容易确定.

但是一开始跑偏了,

开始以为第一个问题的状态转移方程是这个,但是这样时候重复的.

 dp[n, i, k] = dp[n, i - 1, k] + dp[n - i, i, k - 1] + dp[n - i, i - 1, k - 1]

dp[n - i, i, k - 1] = dp[n - i, i - 1, k - 1] + ...

后来翻翻书,自己想了想就想通了.

现在感觉,这种dp问题,一是确认状态转移方程,二是边界条件.

边界条件挺烦人的...

#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 60;
typedef long long ll;
ll dp1[MAXN][MAXN][MAXN];
ll dp2[MAXN][MAXN];
ll dp3[MAXN][MAXN];
int main()
{
    for(int i = 0; i < MAXN; ++i)
        dp1[0][i][0] = 1;//开始我想根据状态转移方程,dp[0, i, 0] -> dp[0, 0, 0]的,但是为了数组不越界,我把j从1开始,所以这里/                        //要这样设置
    for(int i = 1; i < MAXN; ++i)
        for(int j = 1; j < MAXN; ++j)
            for(int k = 1; k < MAXN; ++k)
                if(i >= j)//dp[i, j, k] = dp[i - j, j, k - 1] + dp[i, j - 1, k]
                    dp1[i][j][k] = dp1[i - j][j][k - 1] + dp1[i][j - 1][k];
                else
                    dp1[i][j][k] = dp1[i][j - 1][k];

    for(int i = 0; i < MAXN; ++i)
        dp2[0][i] = 1;
    for(int i = 1; i < MAXN; ++i)
        for(int j = 1; j < MAXN; ++j)
            if(i >= j)//dp[i, j] = dp[i - j] + dp[i][j - 1]
                dp2[i][j] = dp2[i - j][j - 1] + dp2[i][j - 1];
            else
                dp2[i][j] = dp2[i][j - 1];

    for(int i = 0; i < MAXN; ++i)
        dp3[0][i] = 1;
    for(int i = 1; i < MAXN; ++i)
        for(int j = 1; j < MAXN; j+=2)
            if(i >= j && j == 1)//dp[i, j = i - (i + 1)%2] = dp[i - j, j] + dp[i, j - 2] 
                dp3[i][j] = dp3[i - j][j];
            else if(i >= j && j > 1)//这里的条件判断比较麻烦,但我估计能省略一点,emmmm这么麻烦是为了保证j = 1时, j - 2 > 0
                dp3[i][j] = dp3[i - j][j] + dp3[i][j - 2];
            else if(j > 1)
                dp3[i][j] = dp3[i][j - 2];
            else
                dp3[i][j] = 0;
    
    int n, k;
    while(cin >> n >> k){
        cout << dp1[n][n][k] << endl;
        cout << dp2[n][n] << endl;
        cout << dp3[n][n - (n + 1)%2] << endl;
    }
    return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值