[迭代加深]Addition Chains

友情♂链接

题目大意

已知一个数列,其中(a_1=0,a_m=n,a_1<a_2<a_3....<a_m)对于每一个k,满足a_k = a_i + a_j,i,j可相等。

给定n(<=100),输出最小m的数列。

样例输入

5
7
12
15
77
0

样例输出

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

解题思路

首先,数据并不很大,看起来是可以暴力出奇迹的。

然而题目数据多,并且一些特殊的数据,即便题目数据并不大也会很慢。

因此我们需要进行优化。

它要让我们输出最小的m的数列,其实也就是明摆着告诉我们去从小到大枚举m,这样我们就可以完成了。

对于一个数,m是一定会有下限的。其下限其实就是最大的2的k次方小于n。

至于为什么是这样,我们所构造的数列其实就是a[i] = a[i - 1] * 2。又是升序排列,一定最大。

但这样并不能过。

我们还需优化,请看下面这一段代码

for (int i = dep - 1;i >= 1;i --){
		for (int j = i;j >= 1;j --){
			/*if (a[inde][i] + a[inde][j] < a[inde][dep - 1])
				continue;*/
			/*int sum = a[inde][i] + a[inde][j];
			for (int k = dep + 2;k <= max_dep; k ++)
				sum *=2;
			if (sum < inde)
				return ;*/
			a[inde][dep] = a[inde][i] + a[inde][j];
			dfs(inde,dep + 1,max_dep);
			if (flag == 1)
				return ;
		}
	}

注释的便是优化代码

第一个其实就是判断合不合格,数列要求升虚。大家别小看这一个优化,这真的是非常有用的剪枝,有这一个就可以A了。然而当时做也就只会暴力了。

第二个优化其实就是一个判断,也就是后面全部取最大,但都达不过要求的值,我们就不用在进行遍历。

不得不说还是比较水。

#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstdlib>
using namespace std;
int n,a[1005][30];
bool flag ;
void dfs(int inde,int dep,int max_dep){
	if (a[inde][dep - 1] == inde){
		a[inde][0] = dep - 1;
		flag = 1;
		return ;
	}
	if (max_dep < dep || a[inde][dep - 1] > inde)
		return ;
	for (int i = dep - 1;i >= 1;i --){
		for (int j = i;j >= 1;j --){
			/*if (a[inde][i] + a[inde][j] < a[inde][dep - 1])
				continue;*/
			/*int sum = a[inde][i] + a[inde][j];
			for (int k = dep + 2;k <= max_dep; k ++)
				sum *=2;
			if (sum < inde)
				return ;*/
			a[inde][dep] = a[inde][i] + a[inde][j];
			dfs(inde,dep + 1,max_dep);
			if (flag == 1)
				return ;
		}
	}
}
int solve(int xx){
	int t = 1,tot = 1;
	while (t < xx){
		tot ++;
		t *= 2;
	}
	return tot;
}
int main(){
	for (int ii = 2;ii <= 100;ii ++){
		flag = 0;
		a[ii][1] = 1;
		int j = solve(ii);
		for (;;j ++){
			dfs(ii,2,j);
			if (flag == 1)
				break;
		}
	}
	while (scanf ("%d",&n)){
		flag = 0;
		if (n == 0)
			return 0;
		if (n == 1){
			printf("1\n");
			continue;
		}
		for (int i = 1;i < a[n][0];i ++)
			printf("%d ",a[n][i]);
		printf("%d\n",a[n][a[n][0]]);
	}
}

考试的时候心灰意冷,决定打表....毕竟n只有100,然而最后放弃了

猜你喜欢

转载自blog.csdn.net/weixin_43904950/article/details/89515118