蓝桥网 历届试题 九宫重排

问题描述
  如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。

 

我们把第一个图的局面记为:12345678.
  把第二个图的局面记为:123.46758
  显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
  本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入格式
  输入第一行包含九宫的初态,第二行包含九宫的终态。
输出格式
  输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
样例输出
3
样例输入
13524678.
46758123.
样例输出
22

 

 

结题思路:这一题就是纯粹的bfs(),问题就是出在如何保存一个局面?那就是把这个局面映射到一个哈希值,以下代码init_table()和insert_table()就是进行了哈希处理。返回这个排列的大小,即在全部的排列中排第几,其他的就没有了.

 

AC代码;

 

# include <stdio.h>
# include <string.h>
# include <algorithm>
# include <queue>
using namespace std;
typedef long long int ll;
struct node{
	char a[12];
	int cnt;
};
queue<node> q;
int g[5][5], f[12], vis[363000];
void init_table();
int insert_table(char *);
int main(){
	int i, j ,k;
	char s[12], d[12], ch;
	scanf("%s", s);
	scanf("%s", d);
	for(i=0; i<9; i++){
		if(s[i]=='.'){
			s[i]='0';break;
		}
	}
	for(i=0; i<9; i++){
		if(d[i]=='.'){
			d[i]='0';break;
		}
	}
	for(i=1; i<=3; i++){
		for(j=1; j<=3 ;j++){
			g[i][j]=1;
		}
	}
	node front;
	memcpy(front.a, s, sizeof(s));
	front.cnt=0;
	insert_table(front.a);
	q.push(front);
    init_table();
	while(!q.empty()){
		node e=q.front();
		int cnt=e.cnt;
		char tchar[12];
		q.pop();
		if(memcmp(e.a, d, sizeof(d))==0){
			printf("%d", e.cnt);
			return 0;
		}
		for(i=0; i<9; i++){
			if(e.a[i]=='0'){
			    break;
			}
		}
		int x=i/3+1, y=i%3+1;
		if(g[x+1][y]){
			memcpy(tchar, e.a, sizeof(e.a));
			ch=tchar[i];tchar[i]=tchar[i+3];tchar[i+3]=ch;
			if(insert_table(tchar)){
				node temp;
				temp.cnt=e.cnt+1;
				memcpy(temp.a, tchar, sizeof(tchar));
				q.push(temp);
			}
		}
		if(g[x-1][y]){
			memcpy(tchar, e.a, sizeof(e.a));
			ch=tchar[i];tchar[i]=tchar[i-3];tchar[i-3]=ch;
			if(insert_table(tchar)){
				node temp;
				temp.cnt=e.cnt+1;
				memcpy(temp.a, tchar, sizeof(tchar));
				q.push(temp);
			}
		}
		if(g[x][y-1]){
			memcpy(tchar, e.a, sizeof(e.a));
			ch=tchar[i];tchar[i]=tchar[i-1];tchar[i-1]=ch;
			if(insert_table(tchar)){
				node temp;
				temp.cnt=e.cnt+1;
				memcpy(temp.a, tchar, sizeof(tchar));
				q.push(temp);
			}
		}
		if(g[x][y+1]){
			memcpy(tchar, e.a, sizeof(e.a));
			ch=tchar[i];tchar[i]=tchar[i+1];tchar[i+1]=ch;
			if(insert_table(tchar)){
				node temp;
				temp.cnt=e.cnt+1;
				memcpy(temp.a, tchar, sizeof(tchar));
				q.push(temp);
			}
		}
	}
	printf("-1");
	return 0;
}
void init_table(){
	f[0]=1;
	for(int i=1; i<9; i++){
		f[i]=f[i-1]*i;
	}
}
int insert_table(char* p){
	int cnt;
	int sum=0;
	for(int i=0; i<9; i++){
		cnt=0;
		for(int j=i+1; j<9; j++){
			if(p[i]>p[j]){
				cnt++;
			}
		}
		sum=sum+cnt*f[8-i];
	}
	if(vis[sum])return 0;
	else return vis[sum]=1;
}

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值