《搜索》— POJ 2248 Addition Chains(DFS)

Addition Chains

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 5218 Accepted: 2810 Special Judge

Description

An addition chain for n is an integer sequence with the following four properties: 

  • a0 = 1 
  • am = n 
  • a0 < a1 < a2 < ... < am-1 < am 
  • For each k (1<=k<=m) there exist two (not necessarily different) integers i and j (0<=i, j<=k-1) with ak=ai+aj


You are given an integer n. Your job is to construct an addition chain for n with minimal length. If there is more than one such sequence, any one is acceptable. 
For example, <1,2,3,5> and <1,2,4,5> are both valid solutions when you are asked for an addition chain for 5.

Input

The input will contain one or more test cases. Each test case consists of one line containing one integer n (1<=n<=100). Input is terminated by a value of zero (0) for n.

Output

For each test case, print one line containing the required integer sequence. Separate the numbers by one blank. 
Hint: The problem is a little time-critical, so use proper break conditions where necessary to reduce the search space. 

Sample Input

5
7
12
15
77
0

Sample Output

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

Source

Ulm Local 1997

大概题意:
一个整数n的加法链就是一个满足下面性质的序列:
a0 = 1
am = n
a0 < a1 < a2 < ... < am-1 < am
对于每个k (1<=k<=m) 存在两个整数 (不一定不同) i 和 j (0<=i, j<=k-1) 有ak=ai+aj
你被给定一个n,你的工作是构造一个最短长度的加法链,假设这样的序列超过一个,任何一个合适的序列均可。输入包括很多种测试实例,每个测试实例由一行组成,即就是n,然后输出这个加法链的数字序列。

解题思想:
由于每个数字都是由前面的两个数字之和。并且要使这个数字链最短。那么我们可以深搜一下,假设后面的数是由前面的两个数字的和,前面的两个数是我们可以逐渐往前扫描,那么算符就是前面的两个数相加,得到后面的数,这样深搜下去,并且记录找到解后这个数据链的长度。当数据长度最短时即为所求的解,这里为了加快寻找速度,对于一些不必要搜索的我们不需要去搜索,于是就把它剪去。

 


#include<stdio.h>
using namespace std;

int n,len,num[20],ans[20];

void dfs(int dep)
{
	int i;
	if(dep > len)   return ;   //剪枝1
	
	if(num[dep-1] == n)
	{
		if(dep < len)
		{
			len = dep;
			for(i = 0; i < dep; i++)
			{
				ans[i] = num[i];
			}
		}
		return ;
	 } 
	 
	 for(i = dep - 1; i >= 0; i--)
	 {
	 	num[dep] = num[i] + num[dep-1];
	 	if(num[dep]  > n)
	 	{
	 		continue;    //剪枝2 
		}
		dfs(dep+1); 
	 }
} 

int main()
{
	int i;
	while(scanf("%d",&n)&&n)
	{
		len = 11;
		num[0] = 1;
		dfs(1);
		for(i = 0; i < len; i++)
		{
			printf("%d ",ans[i]);
		}
		printf("\n");
	}
	return 0;
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值