八数码 HDU - 1043(状态压缩,宽搜)

题面

题意

3*3的方格中有一个x,可以将x与它相邻的方块交换,使最终结果为
1 2 3
4 5 6
7 8 x

方法

用康拓展开式的方法,状压(也可以采用哈希表),然后通过不断的转换实现用1~362880(9!)来记录3*3中数字的状态
记录时,用9来代替x
再进行宽搜(从最终状态开始),用一个数组来记录达到各个状态之前的状态,并用另一个数组记录这次的移动
注意,因为是从最后的状态开始,所以方向与答案相反

代码

#include
#define N 400000
using namespace std;

struct str
{
	int zt,last;
};
queue<str>q;
int vis[N],a[4][4],aa=0,jc[10]={1,1,2,6,24,120,720,5040,40320,362880},ans[N];
char ch,ea[N];
bool P[10],da[N];

int kt1(string u)//将数字方格转化为康拓展开式
{
	int cnt,sum=1,i,j;
	for(i=0;i<9;i++)
	{
		cnt=0;
		for(j=i+1;j<9;j++)
		{
			if(u[i]>u[j]) cnt++;
		}
		sum+=(cnt*jc[8-i]);
	}
	return sum;
}

string kt2(int u)//将康拓展开式转化为数字方格
{
	int i,j,k,t;
	char an[10];
	u--;
	for(i=1;i<=9;i++) P[i]=0;
	for(i=0;i<=8;i++)
	{
		k=1;
		while(u>=jc[8-i]*k) k++;
		u-=(k-1)*jc[8-i];
		t=1;
		k--;
		while(P[t]) t++;
		while(k)
		{
			while(P[t]) t++;
			t++;
			k--;
		}
		while(P[t]) t++;
		P[t]=1;
		an[i]=t+48;
	}
	an[9]=0;
	return an;
}

int main()
{
	int i,j,x,y,t;
	string k;
	str tmp,tmp2;
	
	tmp.zt=1;
	tmp.last=-1;
	vis[1]=1;
	ans[1]=-1;
	da[1]=1;
	q.push(tmp);
	while(!q.empty())
	{
		tmp=q.front();
		q.pop();
		k=kt2(tmp.zt);
		da[tmp.zt]=1;
		for(i=0;i<9;i++)
		{
			a[i/3+1][i%3+1]=k[i]-48;
			if(k[i]=='9')
			{
				x=i/3+1;
				y=i%3+1;
			}
		}
		//up
		if(x!=1)
		{
			k="";
			swap(a[x][y],a[x-1][y]);
			for(i=1;i<=3;i++)
			{
				for(j=1;j<=3;j++)
				{
					k+=a[i][j]+48;
				}
			}
			if(!vis[kt1(k)])
			{
				vis[kt1(k)]=1;
				tmp2.last=tmp.zt;
				tmp2.zt=kt1(k);
				q.push(tmp2);
				ans[tmp2.zt]=tmp.zt;
				ea[tmp2.zt]='d';
			}
			swap(a[x][y],a[x-1][y]);
		}
		//down
		if(x!=3)
		{
			k="";
			swap(a[x][y],a[x+1][y]);
			for(i=1;i<=3;i++)
			{
				for(j=1;j<=3;j++)
				{
					k+=a[i][j]+48;
				}
			}
			if(!vis[kt1(k)])
			{
				vis[kt1(k)]=1;
				tmp2.last=tmp.zt;
				tmp2.zt=kt1(k);
				q.push(tmp2);
				ans[tmp2.zt]=tmp.zt;
				ea[tmp2.zt]='u';
			}
			swap(a[x][y],a[x+1][y]);
		}
		//left
		if(y!=1)
		{
			k="";
			swap(a[x][y],a[x][y-1]);
			for(i=1;i<=3;i++)
			{
				for(j=1;j<=3;j++)
				{
					k+=a[i][j]+48;
				}
			}
			if(!vis[kt1(k)])
			{
				vis[kt1(k)]=1;
				tmp2.last=tmp.zt;
				tmp2.zt=kt1(k);
				q.push(tmp2);
				ans[tmp2.zt]=tmp.zt;
				ea[tmp2.zt]='r';
			}
			swap(a[x][y],a[x][y-1]);
		}
		//right
		if(y!=3)
		{
			k="";
			swap(a[x][y],a[x][y+1]);
			for(i=1;i<=3;i++)
			{
				for(j=1;j<=3;j++)
				{
					k+=a[i][j]+48;
				}
			}
			if(!vis[kt1(k)])
			{
				vis[kt1(k)]=1;
				tmp2.last=tmp.zt;
				tmp2.zt=kt1(k);
				q.push(tmp2);
				ans[tmp2.zt]=tmp.zt;
				ea[tmp2.zt]='l';
			}
			swap(a[x][y],a[x][y+1]);
		}
	}
	
	while(~scanf("%c",&ch))
	{
		k="";
		if(ch=='x') ch='9';
		i=1;
		if(ch>='0'&&ch<='9')
		k+=ch,i++;
		for(;i<=9;i++)
		{
			scanf("%c",&ch);
			if(ch=='x') ch='9';
			if(ch<'0'||ch>'9')//若读到空格,跳过
			{
				i--;
				continue;
			}
			k+=ch;
		}
		t=kt1(k);
		if(!da[t])
		{
			printf("unsolvable\n");
			continue;
		}
		while(t!=-1)
		{
			printf("%c",ea[t]);
			t=ans[t];
		}
		printf("\n");
		ch=getchar();
	}
}

你可能感兴趣的:(经典,搜索)