XXX 每天都被无数的人膜拜,已经被连续膜拜了 n 天,他发现每天来膜拜自己的人数是一个递增的数列。第一天只有一个人来膜拜,从第二天开始的每一天来膜拜 XXX 的人数都是之前某两天的和。现在 XXX 告诉我们今天有 m 个人来膜拜自己,让我们求使被膜拜天数 n 最小的数列。如果有多组解,任意输出一种即可。
这题没有天数,直接搜索会没有范围
但其实有一个共同的特点是保证天数最小的搜索
联想到埃及分数,迭代加深是最好的选择,每次限制层数,也就是个数就可以了
但迭代加深要有限制条件的搜索
显然这道题的数列是递增的,这是一个可以说是最优化剪枝(obivously)
同时如果在该限制深度下,以最快的增速方式(也就是每天都把上一天*2)都不足以到达目标那么就可以剪枝了,也就是我们的可行性剪枝,位运算一搞就行了
这道题告诉我复习生日蛋糕打暴力可能会有惊喜
另外能水过50分数据的贪心(错误的)
由于可以复制自己,就相当于是左移1,联想到二进制
把一个数拆成二进制的和
每次尝试要凑这个数前i项2次幂的和
例如11=1+2+8
有1了,就是前1项和
然后复制1变成2,发现要用这个幂
凑前两项和3于是1+2
搞完一次后复制2成4,4不需要,复制成8,需要,于是直接加上去就有11
简述这个错误算法就是1位答案+2,0位+1,最后总体-1
实测50(鬼知道数据怎么出的)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int n,ans,s[1001]; 7 void pr(){ 8 cout<<ans<<endl; 9 for (int i = 1; i < ans; i++) 10 cout<<s[i]<<" "; 11 cout<<s[ans]<<endl; 12 exit(0); 13 } 14 int dfs(int depth){ 15 if(s[depth-1]==n) pr();//如果搜到了符合的答案就输出 16 if(depth>ans) return 0;//限制搜索层数 17 for(int i=depth-1;i>=1;--i){ 18 for(int j=depth-1;j>=i;--j){ 19 s[depth]=s[i]+s[j];//今天是前面两天的和 20 if(s[depth]<<(ans-depth)<n) break;//如果剩下的所有 21 if (s[depth] < s[depth - 1]) break;//因为要满足递增J又是倒着枚举的所以满足单调的性质 就可以直接break掉 22 dfs(depth+1); 23 } 24 } 25 return 0; 26 } 27 int main(){ 28 ios::sync_with_stdio(false); 29 cin>>n; 30 s[1]=1;ans=1; 31 while(!dfs(2)) ++ans; 32 }