洛谷 P2578 [ZJOI2005]九数码游戏【bfs+康托展开】

只有9!=362880个状态,用康托展开hash一下直接bfs即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=1000005,fac[]={1,1,2,6,24,120,720,5040,40320,362880},d1[]={4,1,2,7,5,3,8,9,6},d2[]={1,2,3,6,4,5,7,8,9};
int a[15],b[15],v[15],dis[N],la[N],tot;
long long s,t=123456789,ans[N];
int has(long long x)
{
	for(int i=9;i>=1;i--)
		a[i]=x%10,x/=10;
	int r=0;
	for(int i=1,sm;i<=9;i++)
	{
		sm=0;
		for(int j=i+1;j<=9;j++)
			if(a[j]<a[i])
				sm++;
		r+=fac[9-i]*sm;
	}
	return r;
}
long long rel(int x)
{
	memset(v,0,sizeof(v));
	long long r=0;
	for(int i=9;i>=1;i--)
	{
		int t=x/fac[i-1];
		x%=fac[i-1];
		for(int j=1,w=0;j<=9;j++)
			if(!v[j])
			{
				w++;
				if(w==t+1)
				{
					r=r*10+j;
					v[j]=1;
					break;
				}
			}
	}
	return r;
}
int main()
{
	for(int i=1,x;i<=9;i++)
		scanf("%d",&x),s=s*10+x+1;
	s=has(s),t=has(t);//cerr<<s<<" "<<t<<"   "<<rel(s)<<" "<<rel(t)<<endl;
	queue<int>q;
	dis[s]=1;
	q.push(s);
	while(!q.empty())
	{
		int u=q.front();//cerr<<u<<endl<<rel(u)<<endl;
		q.pop();
		if(u==t)
			break;
		long long x=rel(u),v1=0,v2=0;
		for(int i=9;i>=1;i--)
			a[i]=x%10,x/=10;
		for(int i=0;i<9;i++)
			v1=v1*10+a[d1[i]],v2=v2*10+a[d2[i]];//cerr<<v1<<" "<<v2<<endl;
		v1=has(v1),v2=has(v2);//cerr<<v1<<" "<<v2<<endl;
		if(!dis[v1])
			la[v1]=u,dis[v1]=dis[u]+1,q.push(v1);
		if(!dis[v2])
			la[v2]=u,dis[v2]=dis[u]+1,q.push(v2);
	}
	if(!dis[t])
	{
		puts("UNSOLVABLE");
		return 0;
	}
	printf("%d\n",dis[t]-1);
	for(int i=t;i!=s;i=la[i])
		ans[++tot]=rel(i);
	ans[++tot]=rel(s);
	for(int i=tot;i>=1;i--)
	{
		for(int j=1;j<=9;j++)
			a[j]=ans[i]%10-1,ans[i]/=10;
		printf("%d %d %d\n%d %d %d\n%d %d %d\n\n",a[9],a[8],a[7],a[6],a[5],a[4],a[3],a[2],a[1]);
	}
	return 0;
}
posted @ 2018-10-11 10:22  lokiii  阅读(241)  评论(0编辑  收藏  举报