本文主要是介绍【习题·搜索】Bookcase(IDA*),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
题目描述
有N(1 <=N <= 15)本书,每本与每本的高度都不一样。现在可以按照以下的办法整理书:抽出一摞书,再保持原来的顺序插进一个位置。这样的话我们称之为“一次操作”。现在你需要求出至少需要经过几次操作才能让书变成按高度升序的状态。如果需要5次或者多于5次,只需要输出“5 or more”。
题解
如果暴力考虑搜索:我们将 L L L- R R R的书放到 K K K后面,此时一定满足 K > R K>R K>R,否则与先前重复枚举;此时这些书的序列就会有:序列 L L L- R R R和序列 R + 1 R+1 R+1- K K K进行交换,我们使用临时数组存储即可。
因为输出不超过五部,我们需要使用迭代加深搜索。
然后考虑能否设计出一个适当的估价函数利用IDA*算法解决;显然每次进行移动操作的时候,会有三个点的后继发生改变,即 L − 1 L-1 L−1, R R R和 K K K的后继;如果满足 a [ i ] + 1 = a [ i + 1 ] a[i]+1=a[i+1] a[i]+1=a[i+1],则 i + 1 i+1 i+1是 i i i的正确后继,如若每一个序列的错误后继为 t o t tot tot,则可以令函数值 = ⌈ t o t ⌉ =\lceil tot \rceil =⌈tot⌉,即每一次最多修改三个后继使其变正确。
代码
#include <cstdio>
#include <cstring>
#include <iostream>using namespace std;int n;
int a[20];inline int read()
{int s=0;char c=getchar();while (c<'0' || c>'9') c=getchar();while (c>='0' && c<='9') s=s*10+c-48, c=getchar();return s;
}inline int func(void)
{int tot=0;for (int i=1;i<=n;++i) if (a[i]+1!=a[i+1]) tot ++;return tot;
}void change(int L,int R,int K)
{int t[20] = {}, c=0;for (int i=R+1;i<=K;++i) t[++c]=a[i];for (int i=L;i<=R;++i) t[++c]=a[i];for (int i=L;i<=K;++i) a[i]=t[i-L+1];
}bool dfs(int deep,int MAXD)
{int b[20]={}; if (deep==MAXD){if (!func()) return 1;return 0;}int G=func();G=G%3 ? G/3+1 : G/3;if (deep+G>=5) return 0; //IDA*剪枝memcpy(b,a,sizeof(b));for (int L=1;L<=n;++L) for (int R=L;R<=n;++R) for (int K=R+1;K<=n;++K) {//交换 L - R 和 R+1 - Kchange(L,R,K);if (dfs(deep+1,MAXD)) return 1;memcpy(a,b,sizeof(a));} return 0;
}
int main(void)
{freopen("b.in","r",stdin);freopen("b.out","w",stdout);int T;T=read();Again:bool flag=0;n=read();a[n+1]=n+1;for (int i=1;i<=n;++i) a[i]=read();for (int i=0;i<=4;++i)if (dfs(0,i)) {printf("%d\n",i);flag=1;break;}if (!flag) puts("5 or more");if (--T) goto Again;return 0;
}
这篇关于【习题·搜索】Bookcase(IDA*)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!