ZOJ2477 IDA*搜索进阶

版权声明:那个,最起码帮我加点人气吧,署个名总行吧 https://blog.csdn.net/qq_41670466/article/details/84963388

问题大意就是给你一个魔方,让你在五步之内还原这个魔方,这个魔方只能让每个面进行顺时针或者逆时针操作,问能否在五步内解决战斗,如果可以,请输出每一步转动的面,以及是逆时针还是顺时针。

分析:对于这个问题,核心在于如何魔方的转动,以及预估函数的判断;  关于预估函数,我的观点是当你想出正确的模拟转动过程后这个预估函数也就很好写了,所以先对魔方转动模拟的分析:首先可以知道每转动一次都会有20个方块改变位置,而且对于这道题下的魔方可以有12种移动方法(每个面都可以转,且每个面都有两种转法)于是就大胆的写出来这12种的魔方方块移动位次。

同时我们也可以知道一个魔方的还原判断标准是每一个面的外围8个方块与中心相同,于是预估函数也就可以写出,那就是判断每个面都有几个跟中心不相同的方块,逐面累加,然后把这个数除以12,向上取整就得到在理想情况下的剩余步数

代码:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>

using namespace std;

int n,m,depth;
int ans[10],dir[10];
char a[100];

int centre[6]={5,23,26,29,32,50};
int row[6][10] = { {1, 2, 3, 4, 5, 6, 7, 8, 9},          {10, 11, 12, 22, 23, 24, 34, 35, 36},
					  {13, 14, 15, 25, 26, 27, 37, 38, 39}, {16, 17, 18, 28, 29, 30, 40, 41, 42},
					  {19, 20, 21, 31, 32, 33, 43, 44, 45}, {46, 47, 48, 49, 50, 51, 52, 53, 54} };

int change[12][20]={//12表示12种操作,20是因为每一种操作都会导致20个格子发生变化;
    {12, 24, 36, 35, 34, 22, 10, 11, 13, 25, 37, 46, 49, 52, 45, 33, 21, 1, 4, 7},
	{10, 11, 12, 24, 36, 35, 34, 22, 1, 4, 7, 13, 25, 37, 46, 49, 52, 45, 33, 21},
	{15, 27, 39, 38, 37, 25, 13, 14, 16, 28, 40, 48, 47, 46, 36, 24, 12, 7, 8, 9},
	{13, 14, 15, 27, 39, 38, 37, 25, 7, 8, 9, 16, 28, 40, 48, 47, 46, 36, 24, 12},
	{18, 30, 42, 41, 40, 28, 16, 17, 19, 31, 43, 54, 51, 48, 39, 27, 15, 9, 6, 3},
	{16, 17, 18, 30, 42, 41, 40, 28, 9, 6, 3, 19, 31, 43, 54, 51, 48, 39, 27, 15},
	{21, 33, 45, 44, 43, 31, 19, 20, 3, 2, 1, 10, 22, 34, 52, 53, 54, 42, 30, 18},
	{19, 20, 21, 33, 45, 44, 43, 31, 42, 30, 18, 3, 2, 1, 10, 22, 34, 52, 53, 54},
	{3, 6, 9, 8, 7, 4, 1, 2, 18, 17, 16, 15, 14, 13, 12, 11, 10, 21, 20, 19},
	{1, 2, 3, 6, 9, 8, 7, 4, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10},
	{48, 51, 54, 53, 52, 49, 46, 47, 40, 41, 42, 43, 44, 45, 34, 35, 36, 37, 38, 39},
	{46, 47, 48, 51, 54, 53, 52, 49, 37, 38, 39, 40, 41, 42, 43, 44, 45, 34, 35, 36}
};

int geth()
{
	int sum=0;
	for(int i=0;i<6;i++)
	{
		for(int j=0;j<9;j++)
			if(a[row[i][j]]!=a[centre[i]])	sum++;
	}
	return sum;
}

int solve(int d)
{
	int h=geth();
	if(d+ceil(h/12.0)>depth)	return 0;
	if(h==0)	return 1;
	char maze[100];
	//memcpy(maze,a,sizeof(a));
	for(int i=0;i<12;i++)
	{
		memcpy(maze,a,sizeof(a));
		for(int j=0;j<20;j++)
			a[change[i][j]]=maze[change[i^1][j]];//这里的^是用来如果i为偶数则+1,若为奇数则i-1,这样使得在减小代码量的前提下进行魔方位置的模拟。
		ans[d]=i/2;
		if(!(i&1))	dir[d]=1;
		else dir[d]=-1;
		if(solve(d+1))
			return 1;
		memcpy(a,maze,sizeof(maze));
	}
	return 0;
}

int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		for(int i=1;i<=54;i++)
			cin>>a[i];
		if(!geth())
		{
			printf("0\n");
			continue;
		}
		for(depth=1;depth<=5;depth++)
			if(solve(0))	break;
		if(depth==6)
			printf("-1\n");
		else 
		{
			printf("%d\n",depth);
			for(int i=0;i<depth;i++)
				printf("%d %d\n",ans[i],dir[i]);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41670466/article/details/84963388
IDA