POJ3460 Booksort(IDA*)

POJ3460 Booksort

题意:给定一个长度为n的序列,每次可以取出其中的一段数,插入任意一个位置,问最少需要几次操作才能使整个序列变为1~n

  • 思路:IDA*+迭代加深搜索
  • 小技巧:将一段数插入到另一段,等价于交换相邻的两端
  • 估价函数:每次操作最多改变三个数的后继,统计错误后继的个数再/3即为最少需要的步数
  • 代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstring>

inline int read()
{
	int x(0),f(1); char ch;
	while(!isdigit(ch=getchar())) if(ch=='-') f=-1;
	while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
	return f*x;
}
#define res register int
const int N=30;
int a[N],n;

inline int f()
{
	int tmp(0);
	for(res i=1 ; i<=n-1 ; i++)
		if(a[i+1]!=a[i]+1) tmp++;
	if(a[n]!=n) tmp++;
	return tmp;
}

//将一段插入到另一段等价于交换相邻的两段
inline void move(int x1,int x2,int x3)
{
	int b[N],j=0;
	for(res i=x2+1 ; i<=x3 ; i++)
		b[++j]=a[i];
	for(res i=x1 ; i<=x2 ; i++)
		b[++j]=a[i];
	for(res i=x1,k=1 ; i<=x3 ; i++,k++)
		a[i]=b[k];
}

int dfs(int depth,int max_dep)
{
	for(res x1=1 ; x1<=n-1 ; x1++)
		for(res x2=x1 ; x2<=n-1 ; x2++)
			for(res x3=x2+1 ; x3<=n ; x3++)
			{
				move(x1,x2,x3);
				int h=f();
				if(!h) return 1;
				else if(depth+(int)ceil((double)h/3)<=max_dep)
				{
					if(dfs(depth+1,max_dep)) return 1;	
				}
				move(x1,x3-(x2-x1)-1,x3);//还原 
			}
	return 0;
}

int main()
{
	int T=read();
	while(T--)
	{
		n=read();
		for(res i=1 ; i<=n ; i++) a[i]=read();
		if(f()==0) 
		{
			puts("0");
			continue;
		}		
		for(res max_dep=1 ; max_dep<=4 ; max_dep++)
		{
			if(dfs(1,max_dep)) {
				printf("%d
",max_dep);
				break;
			}
			if(max_dep==4) puts("5 or more");
		}
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/wmq12138/p/10413100.html