#10021. 「一本通 1.3 例 4」Addition Chains

Addition Chains

题面翻译

题目描述

一个与 n n n 有关的整数加成序列 < a 0 , a 1 , a 2 , . . . , a m > <a_0,a_1,a_2,...,a_m> <a0,a1,a2,...,am> 满足以下四个条件:
1. a 0 = 1 1.a_0=1 1.a0=1
2. a m = n 2.a_m=n 2.am=n
3. a 0 < a 1 < a 2 < . . . < a m − 1 < a m 3.a_0<a_1<a_2<...<a_{m-1}<a_m 3.a0<a1<a2<...<am1<am
4. 4. 4. 对于每一个 k ( 1 ≤ k ≤ m ) k(1≤k≤m) k(1km) 都存在有两个整数 i i i j ( 0 ≤ i , j ≤ k − 1 , i j(0≤i,j≤k-1,i j(0i,jk1,i j j j 可以相等 ) ) ) ,使得 a k = a i + a j a_k=a_i+a_j ak=ai+aj
你的任务是:给定一个整数 n n n ,找出符合上述四个条件的长度最小的整数加成序列。如果有多个满足要求的答案,只需要输出任意一个解即可。
举个例子,序列 < 1 , 2 , 3 , 5 > <1,2,3,5> <1,2,3,5> < 1 , 2 , 4 , 5 > <1,2,4,5> <1,2,4,5> 均为 n = 5 n=5 n=5 时的解。

输入格式

输入包含多组数据。每组数据仅一行包含一个整数 n ( 1 ≤ n ≤ 10000 ) n(1≤n≤10000) n(1n10000) 。在最后一组数据之后是一个 0 0 0

输出格式

对于每组数据,输出一行所求的整数加成序列,每个整数之间以空格隔开。

题目描述

PDF

输入格式

输出格式

样例 #1

样例输入 #1

5
7
12
15
77
0

样例输出 #1

1 2 4 5
1 2 4 6 7
1 2 4 8 12
1 2 4 5 10 15
1 2 4 8 9 17 34 68 77

不会dfs请睡觉

不会叠代dfs请睡觉

大致思路

  • 本题我们不知道dep是多少,甚至连dep的上限也不清楚。

  • 对于枚举次数不明确的题目,我们可以使用迭代加深搜索(IDA)的思路。对这道题目而言,我们可以先从dep=2开始尝试(前提是n!=1),如果dep=2不行,再尝试dep=3,这样一步步增加dep。

	cin>>n;
	while(n!=0){//多组输入
		memset(a,0,sizeof(a));//初始化
		a[1]=1;
		for(int j=maxdep;maxdep<=999999;maxdep++){
			if(dfs(2)){//实际的深度达不到999999
				for(int i=1;i<=maxdep;i++){
					cout<<a[i]<<" ";
				}
				cout<<endl;
				break;
			}
		}
		cin>>n;
	}
  • 每一个数一定等于上一个数加上 之前的数(可以是上一个数),否则的话如果是两个上一个数之前的数相加,那么上一个数就可以得到了,不需要多存一遍

  • 可行性剪枝:数列每增加一个数,这个数的大小最大是在上一个数的基础上*2,如果剩下的长度中每个数都达到最大值,但最后一个数任然小于n则返回

  • 优化搜索顺序:倒序枚举,因为这样能够更快地到达n

int dfs(int dep){
	if(dep>maxdep){
		if(a[dep-1]==n)return 1;
		else return 0;
	}
	for(int i=dep-1;i>=1;i--){
		for(int j=dep-1;j>=i;j--){
			if(a[i]+a[j]<=a[dep-1])continue;
			a[dep]=a[i]+a[j];
			if(dfs(dep+1))return 1;
		}
	}
	return 0;
}

AC CODE

#include<bits/stdc++.h>
using namespace std;
int n,a[49999],maxdep=1;
int dfs(int dep){
	if(dep>maxdep){
		if(a[dep-1]==n)return 1;
		else return 0;
	}
	for(int i=dep-1;i>=1;i--){
		for(int j=dep-1;j>=i;j--){
			if(a[i]+a[j]<=a[dep-1])continue;
			a[dep]=a[i]+a[j];
			if(dfs(dep+1))return 1;
		}
	}
	return 0;
}
int main(){
	cin>>n;
	while(n!=0){
		memset(a,0,sizeof(a));
		a[1]=1;
		for(int j=maxdep;maxdep<=999999;maxdep++){
			if(dfs(2)){
				for(int i=1;i<=maxdep;i++){
					cout<<a[i]<<" ";
				}
				cout<<endl;
				break;
			}
		}
		cin>>n;
	}
	return 0;
} 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值