小明学算术 回溯法

http://www.rqnoj.cn/Problem_286.html

 

小明最近接到了一项算数的作业。黑板上初始时只有一个数1。每次取在黑板上的任意两个数(可以相同)相加,得到另一个数,要求这个数比黑板上已有的任意一个数都大,并把所得的符合要求的和数也写在黑板上。这称为一次操作。当黑板上首次出现指定的整数n(2<=n<=1000)时,停止操作。
小明的加法学得很不好,算一次加法需要很长时间。他希望学编程的你找到一种方案,用最少的操作次数得出指定的数n。

 

 

输入格式

只有一行。包含一个整数n(2<=n<=1000),表示指定的整数。

 

输出格式

两行。第一行一个整数,表示最少操作次数。第二行若干个空格隔开的整数,表示操作结束时黑板上的所有数,按从小到大的顺序输出。若有多组符合要求的解,输出次大的数最大的一组;若还多解,输出第三大的数最大的一组;以此类推。

 

 

 

【样例输入1】

2

【样例输入2】

200

 

 

 

【样例输出1】

1

1 2

【样例输出2】

9

1 2 4 8 16 32 64 128 192 200

 

 

 

这是搜索题,找最优值的一般用回溯法。

 

我自己写了个回溯的程序,提交上去后只有70分,30超时了,后来看了别人的代码,因为他的代码的效率也不高,但是过了,我按他的方法把自己的代码优化了一遍,但是逻辑有点不对,就自己又写了一遍,结果我的代码和他的代码相差无几了。

 

目前还是没有找到很好的剪枝的办法。有的就是找两个加数的时候从后面开始找,也就是从大的往下的找,具体的看代码吧。

 

这题的收获是对搜索到可能解时候的判断应该放在状态的枚举里,有的题目在一层的搜索中,解状态只可能出现一次,而如果我把判断解状态放在状态枚举里,在找到一个解以后我就可以返回了。听不懂?...看看例子吧

 

递归函数,我原来的是:

 

 

 

后来改成了:

 

 

 

只是代码中有一处我还是不明白,就是打问号的地方。

 

被我注释掉的地方,我感觉那样的逻辑才是正确的,但是会超时。用了

 

if( temp <= cvTempSet[len] )

           return 0;

以后,我感觉逻辑貌似不大对,因为有可能cvTempSet[i]+cvTempSet[j]是比cvTempSet[len]小,但是cvTempSet[i-1] + cvTempSet[i-1]有可能比他大啊。然而大多数情况下这种情况似乎不会发生,而且提高了代码的效率,勉强的AC了。

 

 

谁有看到更好的代码,留个链接呗。

 

我的完整代码:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值