洛谷 P1025 [NOIP2001 提高组] 数的划分

一. dfs

因为数据比较小,此题可以用搜索来暴力,需要注意的是:

①因为要考虑重复,所以我们划分个数采用升序,要保证后一个划分的个数要大于等于前一个划分的个数。

②为了防止TLE,要进行适当的剪枝,详情见代码。

#include<bits/stdc++.h>
using namespace std;
int n,k,sum;
int dfs(int kongjian,int weizhi,int floor){
    if(floor==k){  
        if(weizhi==n) sum++;  
        //已划分k份且数字都已划分完,分法+1
        return 0;
    }
    for(int i=kongjian;(k-floor)*i+weizhi<=n;i++){ 
        //这一步剪枝很关键,当你选择划分一份的个数(i)在最小的划分情况(即后面都划分i个)中都>n,必然无解
        dfs(i,weizhi+i,floor+1); 
        //继续搜索
    }
}
int main(){
    scanf("%d%d",&n,&k);
    dfs(1,0,0);   
    //dfs(划分一份的个数,已划分到的数的位置,已划分的份数)
    printf("%d\n",sum);
    return 0;
}

二 . dp

用a[i][j]表示i个数划分j份的分法数.

A.当i<j 母庸质疑,a[i][j]=0

B.当 i=j ,必然只有一种情况,即每份都只放一个,a[i][j]=1

C.当i>j , 有两种情况:

① 分好j份,不再增加新的一份,而是j份里每个都在放入一个数,即加上a[i-j][j]的分法。

② 增加新的一份,放入一个数,即加上a[i-1][j-1]的分法。

#include<bits/stdc++.h>
using namespace std;
int n,k,a[205][15];
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) a[i][1]=1;//只放一份,只有一种情况
    for(int i=2;i<=k;i++) a[1][i]=0;//分的比总数多,无解
    for(int i=2;i<=n;i++){
        for(int j=2;j<=k;j++){
            if(i==j){  //对应B
                a[i][j]=a[i-1][j-1];
            }else if(i>j){ //对应C
                a[i][j]=a[i-1][j-1]+a[i-j][j];
            }else{//对应A
                a[i][j]=0;
            }
        }
    }
    printf("%d\n",a[n][k]);
    return 0;
}

完结撒花~

posted @ 2022-02-13 12:14  Aurora-JC  阅读(133)  评论(0编辑  收藏  举报