友情♂链接
题目大意
已知一个数列,其中对于每一个k,满足,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
");
continue;
}
for (int i = 1;i < a[n][0];i ++)
printf("%d ",a[n][i]);
printf("%d
",a[n][a[n][0]]);
}
}
考试的时候心灰意冷,决定打表....毕竟n只有100,然而最后放弃了