AcWing 170 加成序列 迭代加深

满足如下条件的序列X (序列中元素被标号为1 , 2 , 3 , … , m )被称为“加成序列”:
1、X [ 1 ] = 1 
2、X [ m ] = n 
3、X [ 1 ] < X [ 2 ] < … < X [ m − 1 ] < X [ m ] 
对于每个k (2 ≤ k ≤ m )都存在两个整数i 和j (1 ≤ i , j ≤ k − 1 ,i 和j 可相等),使得X [ k ] = X [ i ] + X [ j ] 。你的任务是:给定一个整数n ,找出符合上述条件的长度m 最小的“加成序列“。如果有多个满足要求的答案,只需要找出任意一个可行解。

输入格式:
输入包含多组测试用例。每组测试用例占据一行,包含一个整数n 。当输入为单行的0 时,表示输入结束。

输出格式:
对于每个测试用例,输出一个满足需求的整数序列,数字之间用空格隔开。每个输出占一行。

数据范围:
1 ≤ n ≤ 100 

思路当搜索树非常深,但是我们能确定答案一定在浅层节点时,就可以使用迭代加深DFS

此题的数据n在1-100,但是答案可能在浅层结点,所以我们可以采用迭代加深。预设置搜索的最大深度len,如果在len时没有满足的,就len++,继续搜索。

每次的dfs与本层的深度和最大深度有关。那么涉及剪枝和递归边界:

1.当本层的深度到达最大深度时,如果数组中最后一个元素恰好为n,返回true,否则返回false;

2.由于s=a[i]+a[j]可能会重复,所以我们在dfs中加一个判重数组vis。

其次,为了提高效率,让s尽快逼近n,我们每次枚举i和j时都从大到小枚举。

当这个数字已经出现过,或者算出的s已经大于了给出的最大值n,或者不满足数组递增的性质s<=a[dep-1], 剪枝

代码如下:

#include <bits/stdc++.h>
using namespace std;
#define N 150
int a[N],n;
bool dfs(int dep,int len){
	if(dep==len) return a[len-1]==n;//如果深度到达设定的最大深度,此时如果数组最后一个元素等于n,返回true,否则返回false 
	bool vis[N]={false};//标记是否已经出现过,防止找重 
	for(int i=dep-1;i>=0;i--){//从大开始枚举,使之更快逼近n 
		for(int j=i;j>=0;j--){
			int s=a[i]+a[j]; 
			//如果此数字已经出现过或者不满足单调递增性质或者此数字已经大于了n,剪枝 
			if(vis[s]||s>n||s<=a[dep-1]) continue; 
			vis[s]=true;
			a[dep]=s;
			if(dfs(dep+1,len)) return true;
		}
	}
	return false;
}
int main(){
	a[0]=1;//规定第一个元素为1 
	while(cin>>n&&n){
		int len=1;//迭代加深,每次设置一个最大深度 
		while(!dfs(1,len)){
			len++;
		}
		for(int i=0;i<len;i++) cout<<a[i]<<" ";
	    puts("");
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值