【广搜】【九数码问题】

【题目描述】

        这是一个很古老的游戏了:有一个3 × 3的活动拼盘(如下图),方格上写有0~8这九个数字。例如:
    3  7  5 
    2  6  1 
    4  8  0 
  利用拼盘背后的旋钮,游戏者每次可以进行以下两种操作之一:1.将拼盘外围的8个方格按顺时针挪一个位置。2.将中间一行向右移动一个位置,最右边的方格被移到最左边。例如:给你一个拼盘的初始状态,你能用最少的操作次数把拼盘变成下图所示的目标状态吗?
    0  1  2 
    3  4  5 
    6  7  8 

【输入格式】

       本题有多组测试数据。
      输入文件中包含三行三列九个数,同行的相邻两数用空格隔开,表示初始状态每个方格上的数字。初始状态不会是目标状态。

【输出格式】

      如果目标状态无法达到,则输出“UNSOLVABLE”(引号不输出)。否则,输出最少的操作次数。


        多组数据从目标状态反搜预处理每一个状态的最小步数,康拓展开去重,询问时判断有无,输出即可。

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
struct que
{
	int a[4][4];
	int d;
};
int mu[4][4],qi[4][4],dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
int f[10]={1,1,2,6,24,120,720,5040,40320,326880};
bool h[10000005];
int ans[10000005];
int key1,key2;
queue<que> q;
void init()
{
	qi[1][2]=1; qi[1][3]=2; qi[2][1]=3;
	qi[2][2]=4; qi[2][3]=5; qi[3][1]=6;
	qi[3][2]=7; qi[3][3]=8;
}
int key(int a[][4])
{
	int ans=0;
	for(int i=3;i<=11;i++)
	{
		int tmp=0;
		for(int j=i+1;j<=11;j++)
		{
			if(a[i/3][i%3+1]>a[j/3][j%3+1]) tmp++;
		}
		ans+=tmp*f[11-i];
	}
	return ans;
}
bool hash(int a[][4])
{
	key1=key(a);
	if(h[key1]) return false;
	else return true;
}
bool bfs()
{
	que r;
	memcpy(r.a,qi,sizeof(qi));
	r.d=0;
	q.push(r);
	key1=key(qi);
	h[key1]=true;
	ans[key1]=0;
	while(!q.empty())
	{
		que u=q.front();
	/*	for(int i=1;i<=3;i++)
		{
			for(int j=1;j<=3;j++)
			{
				printf("%d ",u.a[i][j]);
			}
			printf("\n");
		}
		getchar();*/
		q.pop();
		swap(u.a[2][1],u.a[2][3]);
		swap(u.a[2][1],u.a[2][2]);
		if(hash(u.a))
		{
			memcpy(r.a,u.a,sizeof(u.a));
			r.d=u.d+1;
			h[key1]=true;
			ans[key1]=u.d+1;
			q.push(r);
		}
		swap(u.a[2][1],u.a[2][2]);
		swap(u.a[2][1],u.a[2][3]);
		swap(u.a[1][1],u.a[2][1]);
		swap(u.a[1][1],u.a[3][1]);
		swap(u.a[1][1],u.a[3][2]);
		swap(u.a[1][1],u.a[3][3]);
		swap(u.a[1][1],u.a[2][3]);
		swap(u.a[1][1],u.a[1][3]);
		swap(u.a[1][1],u.a[1][2]);
		if(hash(u.a))
		{
			h[key1]=true;
			ans[key1]=u.d+1;
			memcpy(r.a,u.a,sizeof(u.a));
			r.d=u.d+1;
			q.push(r);
		}
	}
}
int main()
{
	memset(ans,-1,sizeof(ans));
	init();
	bfs();
	while(~scanf("%d",&mu[1][1]))
	{
		for(int i=1;i<=3;i++)
		for(int j=1;j<=3;j++)
		{
			if(i==1&&j==1) continue;
			scanf("%d",&mu[i][j]);
		}
		key1=key(mu);
		if(ans[key1]>=0) printf("%d\n",ans[key1]);
		else printf("UNSOLVABLE\n");
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值