您的位置:首页 > 大数据 > 人工智能

uva529 Addition Chains

2014-09-14 10:25 330 查看
这道题又加深了我对回溯法的认识。

就是给你一个10000以内的数,找到一个最短且各个数字不相等的数列,使得任一数字(第一个除外)都是前面某两个数字的和。

开始我下的pdf看的题,n最大是100,当时就觉得这题出简单了,写了个普通的dfs,再打个表,就能过了,poj上这题n就是100,直接过了(再次吐槽poj的测试数据),但到uva一看,n变成了10000,一下子超时了。就开始想怎么剪枝,但怎么想都只有一种方法而且依然超时。

于是看了下别人的题解,才发现一个很好的方法。。。

用迭代dfs,这样一是在dfs时可以省去很多过深又没有解的分支,更重要的是,由于每次迭代depth是确定的,就提供了一个很好的剪枝途径:若当前最大数乘以剩下的深度次2时还是小于n,就说明这个分支无解,在加上一些小的优化,终于ac了。

这题给我最大的启发就是迭代加深dfs的妙用,虽然这里明显深度是有界的,但迭代法不仅本身在遍历的过程中除去了一些过深的解,而且提供了绝妙的剪枝途径。。。真正理解一种技巧的实现细节与特点,才能用好它

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define MAX 100
using namespace std;

int n,depth,ans[MAX],temp[MAX],ok;

void dfs(int cur)
{
if(cur-1==depth)
{
if(temp[cur-1]==n)
{
ok=1;
memcpy(ans,temp,MAX*4);
}
return ;
}
int i,j,t,viss=0,sum;
char vis[10010];
memset(vis,0,10010);
for(i=cur-1;i>=0;i--)
{
for(j=i;j>=0;j--)
{
if(temp[i]+temp[j]<=temp[cur-1])
break;
if(temp[i]+temp[j]<=n)
{
if(vis[temp[i]+temp[j]]==1)
continue;
vis[temp[i]+temp[j]]=1;
sum=temp[i]+temp[j];
for(t=cur;t<depth;t++)
sum*=2;
if(sum<n)
continue;
temp[cur]=temp[i]+temp[j];
dfs(cur+1);
if(ok==1)
return ;
}
}
}
}

int main()
{
int i,j,sum;
while(scanf("%d",&n)&&n)
{
depth=0,sum=1,ok=0,temp[0]=1,temp[1]=2;
while(sum<n)
{
depth++;
sum*=2;
}
if(n!=1)
for(;ok==0;depth++)
dfs(2);
printf("1");
for(i=1;i<depth;i++)
printf(" %d",ans[i]);
puts("");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: