数的划分

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

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

1,1,5
1,5,1
5,1,1

问有多少种不同的分法。


输入格式:
n,k

 

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


输入样例
7 3


输出样例
4


虽然正解是DP,但还是搜索又好写,又易懂

 

dfs代码:(暴力枚举不解释)

#include<stdio.h>

int ans;
void dfs(int n,int k,int i)
{
    if(k==0 || n==0)
    {
        if(k==0 && n==0)
            ans++;
        return ;
    }
    for(i;i<=n;++i)
        dfs(n-i,k-1,i);
}
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    dfs(n,k,1);
    printf("%d",ans);
}

 

DP做法:

个人认为,能不用DP就不用DP(至少我这样的新手是推不出公式的)

据学长的指导,将情况分为有 1 和没有 1 的情况

如样例

有1:{1,1,5};{1,2,4};{1,3,3}

没1:{2,2,3}

可见,最终的答案可以表示为——ans=“有1”的情况+"没1"的情况

我们用一个 f[i][j] 表示 数值为 i ,j 种分法

有1的情况:f[i-1][j-1]

没1的情况:f[i-j][j]

如样例

7 3 有1的情况与6 2的分法相同

1 1 5    1 5

1 2 4    2 4

1 3 3    3 3

7 3 没1的情况与4 3的分法相同

2 2 3    2 2

So f[i][j]=f[i-1][j-1]+f[i-j][j]

 

正解的DP:

#include<stdio.h>
int f[201][7];
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    f[0][0]=1;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=k;++j)
            if(i>=j){
                f[i][j]=f[i-1][j-1]+f[i-j][j];
            }
    printf("%d",f[n][k]);        
    return 0;
}

 

还有一种该题的变型——放苹果

题意类似,不同之处在于可以放“0”,一个暴搜就可以做的

代码如下

#include<stdio.h>

int divide(int lev,int plat)
{
    if(lev==0 || lev==1 || plat==1) return 1;
    if(lev<plat) return divide(lev,lev);
    return divide(lev-plat,plat)+divide(lev,plat-1);
}

int main() 
{
    int T;
    scanf("%d",&T);
    while(T--) {
        int n,m;
        scanf("%d%d",&n,&m); 
        printf("%d\n",divide(n,m));
    }
    return 0;
}

 

但其实正解还是DP

 

posted @ 2018-08-07 12:01  qseer  阅读(232)  评论(1编辑  收藏  举报