版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ronaldo7_ZYB/article/details/88830134
来源:POJ2248
题目大意
规定第一个数为1,第二个数是2,你需要找到长度为m的序列使得这一个序列中每一个数都有前面的两个相同或不同的数拼凑而成,输出这一个m最小的任意序列方案(SPJ)。
做法
首先需要说一下什么叫做迭代加深搜索。
在某一颗搜索树上,如果答案在这一棵树的浅层那么我们如果在深度较大的子树上搜索就会浪费很多的时间,因此我们需要需要控制搜索的深度,不断的从浅层向深层进行扩展。
具体的做法就是,每次不断枚举一个深度,如果深度超出则退出。例如在本题中,我们就可以从小到大枚举m,如果存在合法解就直接输出即可。
但是迭代加深的限制就是:答案一定在浅层,如果在深层就直接原地爆炸 了;例如在这道题中因为第n很小,即m的大小不会超过n,所以我们可以使用迭代加深搜索。
做一个区分:如果这道题直接使用深度优先搜索算法,那么你的方案已定是朝着不优的防线前进的;例如,最优的m是5,你可能会在m=6,7,8等数中越走越远,因此这道题需要使用迭代加深搜索。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,deep;
int a[200000];
int v[200000];
bool dfs(int x)
{
if (x>deep) return 0;
if (a[x-1]==n) return 1;
for (int i=x-1;i;--i)
for (int j=i;j;--j)
if (a[i]+a[j]>a[x-1] && v[a[i]+a[j]]==0)
{
v[a[i]+a[j]]=1;
a[x]=a[i]+a[j];
if (dfs(x+1)) return v[a[i]+a[j]]=0,1;
v[a[i]+a[j]]=0;
a[x]=0;
}
return 0;
}
int main(void)
{
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
cin>>n;
a[2]+=2*(a[1]=1);
again:
deep=1;
if (n==1) printf("1\n");
else if (n==2) printf("1 2\n");
else
while (true==true)
{
if (dfs(3))
{
for (int i=1;i<deep;++i)
printf("%d%c",a[i],i==deep-1?'\n':' ');
break;
}
deep++;
}
cin>>n;
if (n) goto again;
return 0;
}