ybt1318 自然数拆分(又一手打dfs)

ybt1318 自然数拆分

【题目描述】

任何一个大于1的自然数n,总可以拆分成若干个小于n的自然数之和。

当n=7共14种拆分方法:

7=1+1+1+1+1+1+1
7=1+1+1+1+1+2
7=1+1+1+1+3
7=1+1+1+2+2
7=1+1+1+4
7=1+1+2+3
7=1+1+5
7=1+2+2+2
7=1+2+4
7=1+3+3
7=1+6
7=2+2+3
7=2+5
7=3+4
total=14

【输入】

输入n。

【输出】

按字典序输出具体的方案。

【输入样例】

7

【输出样例】

7=1+1+1+1+1+1+1
7=1+1+1+1+1+2
7=1+1+1+1+3
7=1+1+1+2+2
7=1+1+1+4
7=1+1+2+3
7=1+1+5
7=1+2+2+2
7=1+2+4
7=1+3+3
7=1+6
7=2+2+3
7=2+5
7=3+4

【题解】

观察样例,可以看出每个方案的加数是升序排列的

在一开始,我把这道题想成ybt1200 分解因数的加法版本,但是分解因数只是要求输出方案数,没法输出方案,而且方案数累加过程中,是不按字典序递增的,同样不行。

一开始走的弯路:

如果用分解不行,为什么不把n先看做n个1,然后合并呢?(这只是个猜想,因为没看题解,只能走一步说一步)

但是我想了想就放弃了,毕竟这个单元是搜索嘛!

正解

后来我就又想到可以借鉴爬楼梯的思路(爬楼梯是按照最后一步迈几级分类),把情况按照当前的第一个加数(最小的)分类:先讨论第一个加数是1的情况,全部输出后在讨论第一个加数是2的情况······以此类推,最后一直到第一加数是n/2(向下取整)(因为加数最少两个,而每个加数递增排列,所以最小加数最大为n/2)

这样,就这问题分解了。最小加数为1时,输出1,然后按n=n-1的情况处理。

边界条件就是当n=1时,分解后就是1。

打了一会代码,发现越来越迷茫,一看书上的题解,发现算法没毛病,只是输出有问题,那就继续自己打!

#include<iostream>
using namespace std;
int n,ans[10005];
void dfs(int x,int y) {//x表示还没有分配的n的数字,y表示当前所决定的最小加数位置 
    if(x==1){//只剩一了,不能分解,直接输出(当然,这种情况一个测试点只会执行一次,因为这里1是最后一个加数也就是最大的加数,这种情况只有n个加数均为1才会执行)
        ans[y]=1;//将1作为当前最小加数也是最后一个加数
        cout<<n<<"="<<ans[1];//输出开头和第一个加数
        for(int k=2; k<=y ;k++) {
            cout<<"+"<<ans[k];//输出后面的加数
        } 
        cout<<endl;//方案输出完毕
    }
    else{
        for(int j=ans[y-1];j<=x/2;j++) {
            ans[y]=j;//给当前位赋值
            dfs(x-j,y+1);//再分别以各个j为第y
        }
        ans[y]=x;//也可以选择不分解直接以第y位的x为最后一位
        cout<<n<<"="<<ans[1];//输出
        for(int k=2;k<=y;k++) {
            cout<<"+"<<ans[k];
        }
        cout<<endl;
    }
    return;
}
int main() {
    cin>>n;
    for(int i=1;i<=n/2;i++) {//枚举不同的i,也就是首位最小加数
        ans[1]=i;//首位赋值
        dfs(n-i,2);//讨论后面的位
    }
    return 0;
}

这题也是一道dfs,做题时要注意按照输出顺序来决定算法。

猜你喜欢

转载自www.cnblogs.com/Wild-Donkey/p/12236653.html