1. 程式人生 > >洛谷P2578 [ZJOI2005]九數碼遊戲

洛谷P2578 [ZJOI2005]九數碼遊戲

搜尋好題!

一個有 神器 神奇操作的八數碼

直接逆向BFS,對於每種狀態,判重and記錄擴充套件到他的id,以及給他一個id,搜到輸入的局面後,倒序輸出就行了

程式碼

#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct emm
{
	int b[3][3],co,la,id;
	bool friend operator < (emm x,emm y)
	{return x.co>y.co;}
}ad,no,t[1000500];
priority_queue<emm>q;
int a[4][4],cnt;
bool f[9][9][9][9][9][9][9][9];
inline void cha1()
{
	ad=no;
	ad.b[1][0]=no.b[0][0];ad.b[2][0]=no.b[1][0];

	ad.b[2][1]=no.b[2][0];ad.b[2][2]=no.b[2][1];
	
	ad.b[1][2]=no.b[2][2];ad.b[0][2]=no.b[1][2];

	ad.b[0][1]=no.b[0][2];ad.b[0][0]=no.b[0][1];

	if (f[ad.b[0][0]][ad.b[0][1]][ad.b[0][2]][ad.b[1][0]][ad.b[1][1]][ad.b[1][2]][ad.b[2][0]][ad.b[2][1]]) return ;

	f[ad.b[0][0]][ad.b[0][1]][ad.b[0][2]][ad.b[1][0]][ad.b[1][1]][ad.b[1][2]][ad.b[2][0]][ad.b[2][1]]=1;

	ad.co=no.co+1;ad.la=no.id;ad.id=++cnt;t[cnt]=ad;

	return (void)(q.push(ad));
}
inline void cha2()
{
	ad=no;
	ad.b[1][2]=no.b[1][0];ad.b[1][0]=no.b[1][1];ad.b[1][1]=no.b[1][2];
	
	if (f[ad.b[0][0]][ad.b[0][1]][ad.b[0][2]][ad.b[1][0]][ad.b[1][1]][ad.b[1][2]][ad.b[2][0]][ad.b[2][1]]) return ;
	
	f[ad.b[0][0]][ad.b[0][1]][ad.b[0][2]][ad.b[1][0]][ad.b[1][1]][ad.b[1][2]][ad.b[2][0]][ad.b[2][1]]=1;
	
	ad.co=no.co+1;ad.la=no.id;ad.id=++cnt;t[cnt]=ad;

	return (void)(q.push(ad));
}
inline bool che()
{
	for (int i=0;i<3;i++)
	for (int k=0;k<3;k++)
	if (a[i][k]!=no.b[i][k]) 
	return 0;return 1; 
}
inline void BFS()
{
	for (int i=0;i<3;i++)
	for (int k=0;k<3;k++)
	no.b[i][k]=i*3+k;
	no.co=0;no.id=0;t[0]=no;q.push(no);
	while (q.size())
	{
		no=q.top();q.pop();
		if (che()) return (void)(cout<<no.co);
		cha2();cha1();
	}
	return ;
}
signed main()
{
	for (int i=0;i<3;i++)
	for (int k=0;k<3;k++)
	scanf("%d",&a[i][k]);
	BFS();int e=no.id;puts("");
	while (1)
	{
		for (int i=0;i<3;i++)
		{
			for (int k=0;k<3;k++)
			cout<<t[e].b[i][k]<<" ";
			puts("");
		}
		if (!e) break;
		puts("");e=t[e].la;
	}
	return 0;
}