数的划分

描述

将整数n分成k份,且每份不能为空,任意两份不能相同(不考虑顺序)。

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

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

问有多少种不同的分法。 输出:一个整数,即不同的分法。

输入

两个整数n,k (6 < n <= 200,2 <= k <= 6),中间用单个空格隔开。

输出

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

样例输入

7 3

样例输出

4

提示

四种分法为:1,1,5;1,2,4;1,3,3;2,2,3。

【题目 http://noi.openjudge.cn/ch0206/8787/】

分析

显然是个动规

方程:f[i,j]=f[i-1,j-1]+f[i,j-i]

这题可以看成把N个苹果放在K个盘子里,每个盘子都不能为空(即每个盘子里至少有一个苹果),求方案数

设f[i,j]表示j个苹果放在i个盘子的方案数

初始化很好理解,不管把几个苹果放在一个盘子里都只有一种放法,所以f[1,i]:=1;

好啦,初始化解释完就不管了

现在来看f[i,j]=f[i-1,j-1]+f[i,j-i];

假设现在盘子全为空,苹果都不在盘子里,我们开始放苹果吧!

(1):先在一个盘子里放一个苹果,就剩下j-1个苹果放在i-1个盘子里,有f[i-1,j-1]种放法
(2):再把盘子里的苹果全都拿出来(让盘子全为空),然后再开始放。 这次先在一个盘子里放两个苹果,就剩下j-2个苹果放在i-1个盘子里,有#种放法(先不管‘#’)是多少

(3):再把盘子里的苹果全都拿出来(让盘子全为空),然后再开始放。 这次先在一个盘子里放三个苹果,就剩下j-3个苹果放在i-1个盘子里,有#种放法(不管‘#’)是多少

……

以此类推,直到在一个盘子里放j-i+1个苹果,然后把这些方案数加起来,存在f[i,j]。

先在一个盘子里放一个苹果的方案数已经知道了,就先让f[i,j]=f[i-1,j-1]+%&#@,先不管%&#@是什么,回顾一下前面,从2开始就不好求了,因为你不知道当你先在一个盘子里放M(M>1)个苹果后求出来的方案有没有和前面重复。

那就换种思路来求除了(1)以外的方案数吧

看看题目的约束条件,即每个盘子里至少有一个苹果,为了满足条件,就让每个盘子里都有一个苹果,然后剩下j-i个苹果放在i个盘子里(有个盘子只有一个苹果的情况在(1)已经考虑过了,所以现在每个盘子至少要有两个苹果),而j-i个苹果放在i个盘子里的方案数已经算出来了(f[i,j-i]),每个方案都保证往当前的每个盘子中放至少一个苹果,当前每个盘子里已经都有一个苹果,所以这样一来每个盘子至少有两个苹果,(2)就包括在里面了。以此类推,(3),(4)……也都包括在(如果可能)f[i,j-i]里。所以加上f[i,j-i]就好了。

pascal代码

program sdfg;
var
  n,k,i,j:longint;
  f:array[0..200,0..200] of longint;
begin
  readln(n,k);
  for i:=1 to n do
    f[i,1]:=1;
  for i:=1 to n do
    for j:=2 to i do
      f[i,j]:=f[i-1,j-1]+f[i-j,j];
  writeln(f[n,k]);
end.

c++代码

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cstdio>
#include <queue>
#include <ctime>
#include <cmath>
int f[210][210];
int main()
{
//    freopen("numf.in","r",stdin);
//    freopen("numf.out","w",stdout);
    int n,k,i,j;
    scanf("%d%d",&n,&k);
    for (i=1;i<=n;i++)
      f[i][1]=1;
    for (i=1;i<=n;i++)
      for (j=2;j<=i;j++)  
        f[i][j]=f[i-1][j-1]+f[i-j][j];
    printf("%d",f[n][k]);
    return 0;    
}

这是我第一次写题解,写的不好多多包涵

【这也是我的第一篇博客】

posted @ 2017-11-03 14:35  SAKURA12  阅读(450)  评论(0编辑  收藏  举报