自然数拆分问题的解法与感悟(C++)

好吧,最近准备算法与程序设计竞赛(qwq我发现这个比赛的时候就离比赛时间没几天了好难),开始刷题了,刷到了这个自然数拆分的问题的问题,题目相对来说不难,但是对我来说还是有一些难度的,下面我就来说说这道题的解法和我的一些感悟吧。

先来看看题目。

我先来对题目的需求做一些阐述,题目要求要输入一个自然数,然后相当于找哪些自然数(在这篇文章之后我就叫它们是组成数吧)加起来能等于这个自然数,而组成这个数的自然数的个数不限,当然,很容易知道个数最多就是输入的自然数本身的值。要求是输出的组成数从小到大排列,中间有加号,字典序小的序列需要优先输出。(在这里我还特意查了查按字典序排列是什么意思,简单来说,就是比如有两段序列,那么先比较第一个字符,字符序列小的先输出,如果相同,则比较下一个字符,以此类推,所以说,到我们这个题目上来,1肯定比除了0的其它任何自然数都小,所以肯定首先输出的是全是1的序列,然后输出的序列以此类推,这个比较简单,就不多说了。)

下面回归题目,来找一找解决办法,emmm,自己在做的时候也是查了查解决办法,按照网上的解决办法来写的代码。

首先他要输入一个数字,那肯定要定义一个变量嘛来存储这个数字,在这里我定义为num。然后我们要对num不断拆分,那么经过一次一次的拆分,每次拆分后都会剩下一个值用于之后的在此拆分直至拆分结束,在这里我定义了cur变量来存储当前的拆分剩余值,当然,直接用num也可以,不过我为了更好地区分就没有用num。在输出时,要输出一个序列,所以需要一个数组来存储每次拆分的数字,这个数组我命名为a。(我刷的这道题的话,输入的数字是1到9,所以只定义了10个长度。++)

#include<iostream>
using namespace std;
int cur;//cur存储当前所剩值
int num;//num是输入数
int a[10];//存储拆分的数字
int new_num;//记录最新拆分的数字的下标

定义完相关的变量后我们来说一说整体的一个设计,这道题比较简单啦,所以就是写一个自然数拆分函数,之后在main函数里去调用它。这个题目的核心部分就是拆分函数,所以我们接下来还是主要说一说拆分函数的实现思路吧。

拆分函数的功能就是把自然数拆分,那我们先来考虑一些特殊情况吧,就是说比如他是可以直接输出的情况比如输入0,那他不能再拆分为更小的自然数了,所以在这种情况下我们直接输出就可以,这里可以用一个if结构来实现,还有一种特殊情况就是已经把所输入的数字拆分完了即当前的cur等于0,这时就需要输出了,利用数组将存储的组成数进行输出,需要注意的是,这个时候如果是同时输出数字和加号的话,先不要输出最后一个组成数,如果输出的话,会导致最后结果多一个加号,正确的方法是:利用for循环将组成数输出到倒数第二个,再在for循环外单独起一行进行最后一个组成数的输出,并且记得在这儿加上换行符,不然多个序列之间没法换行。

考虑完了特殊情况,最主要的东西来了,那就是怎么拆分自然数呢?

这里是用到了递归思想的,我将这个函数命名为了void devide(int last),其中last是上次拆分的数字,也就是说,比如上个序列是11111,那这次这个序列就是1112,1就是上次拆分的数字,从上次拆分的数字开始进行拆分,才能拆到2。

除了递归思想,还要用到for循环进行辅助,也就是利用for循环进行枚举,将上次拆分的数字赋值给for循环中的i,在每次循环中,都将i存入a数组中以便之后的输出,在存完之后,将剩余值进行更新,也就是用cur减去拆分值i,之后调用函数本身进行递归,递归完之后,记得要将数字下标和剩余值更新回原状态以便下一次的拆分使用。

内容大概就是这么多啦,下面看看成果吧!

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值