为了能到远方,脚下的每一步都不能少.|

Aurora-JC

园龄:3年粉丝:3关注:4

📂题解
🔖dfsdp
2022-02-13 12:14阅读: 214评论: 0推荐: 1

洛谷 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;
}
复制代码

完结撒花~

本文作者:南风未起

本文链接:https://www.cnblogs.com/jiangchen4122/p/15888584.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Aurora-JC  阅读(214)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起