试题 历届试题 九宫重排(c++------bfs+康托去重)

资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
  如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
在这里插入图片描述在这里插入图片描述
  我们把第一个图的局面记为:12345678.
  把第二个图的局面记为:123.46758
  显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
  本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入格式
  输入第一行包含九宫的初态,第二行包含九宫的终态。
输出格式
  输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
样例输出
3
样例输入
13524678.
46758123.
样例输出
22
/用bfs+康托去重,见代码/

在这里插入代码片
#include<iostream>
#include<string.h>
#include<queue>
#define swap(a,b) {int t = a;a = b;b = t;}
using namespace std;

int mv[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
int visit[362880] = {0};
int start[9];
int end[9];
long int fac[] = {1,1,2,6,24,120,720,5040,40320,362880};    //康托展开会用到的数据  0~9 的阶乘 
struct node{												//定义队列里的类型node 
	int state[9];
	int dis;
};
queue<node>q;
int f(int a[],int n)										//康托展开去重,不会的可以百度找找^-^ 
{
	long result = 0;
	for(int i=0;i<n;i++){
		int c = 0;
		for(int j=1+i;j<n;j++){
			if(a[i] > a[j])                      			//在区间[j,n-1]中找比a[i]大的数字有几个 
			c++;
		}
		result += c*fac[n-i-1];
	}														//最终result就是这个数字在0~9全排列中的位置 
	if(visit[result])
	return 0;
	else{
		visit[result] = 1;
		return 1;
	}
}
int bfs()
{
	node head;
	memcpy(head.state,start,sizeof(start));   //复制起点的状态 
	head.dis = 0;
	q.push(head);								//起点进队 
	f(head.state,9);
	while(!q.empty())                   
	{
		node newnode = q.front();              //访问队头 
		q.pop();							   //出队 
		int pos;							   //找到数字 0 所在的位置 
		for(int i=0;i<9;i++){
			if(newnode.state[i] == 0){
				pos = i;
				break;
			}
		}
		int x = pos/3;                       //转化为二维坐标 
		int y = pos%3;
		for(int i=0;i<4;i++){
			int nx = x+mv[i][0];
			int ny = y+mv[i][1];
			int nz = nx*3+ny;				//转化为一维坐标 
			if(nx<3&&nx>=0&&ny<3&&ny>=0){
				node newhead;
				memcpy(&newhead,&newnode,sizeof(struct node));   //复制出队元素的状态 
				newhead.dis += 1;
				swap(newhead.state[pos],newhead.state[nz]);		//进行交换 
				if(memcmp(newhead.state,end,sizeof(end)) == 0)  //如果与结束态相同就结束 
				return newhead.dis;
				if(f(newhead.state,9))							//利用康拓去重判断这个状态是否出现过 
				q.push(newhead);								//没出现就进队 
			} 
		}
	}
	return -1;                                                   //转换不到结束态就返回-1 
}
int main()						 
{
	int s;
	string s1,s2;
	cin>>s1;
	getchar();
	cin>>s2;
	for(int i=0;i<9;i++){
		if(s1[i] == '.'){
			start[i] = 0;
			s = i;
		}
		else
		start[i] = s1[i] - '0';
		if(s2[i] == '.')
		end[i] = 0;
		else
		end[i] = s2[i] - '0';
	}
	int ans = bfs();
	cout<<ans<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

译制片~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值