P1025 数的划分(DP)

题目描述
将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序)。

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

1,1,5;
1,5,1
5,1,1.

问有多少种不同的分法。

输入输出格式
输入格式:
n,k

输出格式:
1个整数,即不同的分法。

输入输出样例
输入样例#1: 复制
7 3
输出样例#1: 复制
4
说明
四种分法为:
1,1,5;
1,2,4;
1,3,3;
2,2,3.

题解
首先感叹真的是弱。这个DP题状态转移方程真的是想不出来。直到我看到了这道题的另一个题目。。
这题其实是排列组合里的题,可以把一个数值为n的数当做n个小球,划分的份数k当做k个盒子,那么本题可以转化为“将n个小球放到k个盒子中,小球之间与盒子之间没有区别,并且最后的结果不允许空盒”

将n个小球放到k个盒子中的情况总数 =

a.至少有一个盒子只有一个小球的情况数

+b.没有一个盒子只有一个小球的情况数

这样进行划分是因为这种分类可以使a和b都有能写出来的表达式:

a.因为盒子不加区分,那么1的情况数与“将n-1个小球放到k-1个盒子中”的情况数一样

b.没有一个盒子只有一个小球,那么把每个盒子中拿出来一个小球,对应的是“把(n-k)个小球放到k个盒子中的情况数”

然后将上面的思路化为动态转移方程:

设f[n,k]代表将n个小球放到k个盒子中且没有空盒的情况,那么f[n,k] = f[n-1,k-1] + f[n-k,k]

而当k=1时只有1种方法(小球全部放进1个盒子)

代码

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
int dp[205][10];
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        dp[i][1]=1;
        dp[i][0]=1;
    }
    for(int j=2;j<=k;j++)
    {
        dp[1][j]=0;
        dp[0][j]=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;
}

猜你喜欢

转载自blog.csdn.net/qq_41243063/article/details/84895218
今日推荐