洛谷P1025 数的划分【dp】

将整数nn分成kk份,且每份不能为空,任意两个方案不相同(不考虑顺序)。

例如:n=7n=7,k=3k=3,下面三种分法被认为是相同的。

1,1,51,1,5;
1,5,11,5,1;
5,1,15,1,1.

问有多少种不同的分法。

输入输出格式

输入格式:

 

n,kn,k (6<n \le 2006<n≤200,2 \le k \le 62≤k≤6)

 

输出格式:

 

11个整数,即不同的分法。

 

输入输出样例

输入样例#1: 复制

7 3

输出样例#1: 复制

4

说明

四种分法为:
1,1,51,1,5;
1,2,41,2,4;
1,3,31,3,3;
2,2,32,2,3.

思路:常用有两种做法,即dp和递归,dp的话要能推得方程dp[i][j]=dp[i-1][j-1]+dp[i-j][j];分析一下:

1. 当i=j时,此时只能为1

2. 当i<j时,毫无疑问为0

3. 当i>j时,分为两种情况

①有1的 ②没有1的

第一种情况,方案数为 f[i-1][x-1]

第二种情况,方案数为 f[i-x][x] (此时 i 必须大于 x)

所以,状态转移方程为: f[i][x]=f[i-1][x-1]+f[i-x][x]

dfs

关键方程dp(i, sum + i, pos + 1);,其中i为第pos(position)个选取的数,

同时加入边界判断:

1. n - sum >= (dv - pos)意义为剩下的至少可以组合得到n(全取1).

2. pos == i时判断cnt+=(sum==n)? 1 : 0;(cnt表示计数)

#include<cstdio>
#include <iostream>
#include<string>
using namespace std;
const int maxn=205;
//const int Mod=100003;
int dp[maxn][8];
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i)
        dp[i][1]=1;
    for(int i=1;i<=k;++i)
        dp[1][k]=0;
    for(int i=2;i<=n;++i)
    {
        for(int j=2;j<=k;++j)
        {
            if(i>j)
                dp[i][j]=dp[i-1][j-1]+dp[i-j][j];
            else
                dp[i][j]=dp[i-1][j-1];
        }
    }
    printf("%d\n",dp[n][k]);
    return 0;
}

 

posted @ 2018-10-08 16:45  浮生惘语  阅读(190)  评论(0编辑  收藏  举报