题解 UVA529 【Addition Chains】
迭代加深+剪枝 看完题目第一反应求最短路:bfs;看了一眼n=10000,肯定会爆空间。因此考虑dfs,按照dfs去跑会发现暴力dfs可能得不到正确答案;转念一想这不就是dfs形式的bfs吗?这不就是迭代加深??
快速写完迭代加深后样例数据一发就过了,信心倍增;但是输入10000之后发现它好像不动了。。。。。这样一定会T;
考虑剪枝,不难看出我们需要的序列是单调递增的,枚举i,j得到k;因此如果发现ans[i]+ans[j]>n,那么如果i不变,j往后增一定也大于n;不过这并不会有什么大的改观;
强剪枝:ans[i]<=ans[i-1]2,也就是说后一项最多是前一项的2倍,如果当前已知ans[k]然后迭代加深的最大深度为maxd,则后面最多还有maxd-k项,也就是说ans[k]2^k<n则在maxd次之内一定找不到答案。
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
long long n,maxd,ans[N];
bool dfs(int k){
if(k>maxd)return ans[k-1]==n;
if(ans[k-1]*((long long)1<<(maxd-k+1))<n)return 0;//最优化剪枝:后面每一项最多是前一项的2倍
for(int i=0;i<k;i++)
for(int j=i;j<k;j++){
long long t=ans[i]+ans[j];
if(t>n)break;//可行性剪枝:ans单调递增,如果t>n则后面的j都会大于n;
if(t<=ans[k-1])continue; //保证ans单调递增
ans[k]=t;
if(dfs(k+1))return 1;
}
return 0;
}
int main(){
ans[0]=1;
while(scanf("%lld",&n)&&n){
printf("1");
for(maxd=0;;maxd++){
if(dfs(1)){
for(int i=1;i<=maxd;i++)
printf(" %lld",ans[i]);
printf("\n");
break;
}
}
}
return 0;
}