百练#1077Eight(hash实例)

描述
八数码问题,目标固定为123456780,输出路径。
输入
You will receive a description of a configuration of the 8 puzzle. The description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus ‘x’. For example, this puzzle

1 2 3
x 4 6
7 5 8

is described by this list:

1 2 3 x 4 6 7 5 8

输出
You will print to standard output either the word ``unsolvable’’, if the puzzle has no solution, or a string consisting entirely of the letters ‘r’, ‘l’, ‘u’ and ‘d’ that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line.
样例输入

2 3 4 1 5 x 7 6 8

样例输出

ullddrurdllurdruldr

#include<iostream>
#include<cstring>
using namespace std;
const int MAX = 1000000;
const int d[4][2] = {{0,-1},{-1,0},{0,1},{1,0}};
int st[MAX][9];//宽搜的队列,保存的是图的状态
int dist[MAX],goal[9] = {1,2,3,4,5,6,7,8,0};
int head[MAX],nnext[MAX];//链地址法的哈希表
int fa[MAX]; 
int Hash(int s){//地址映射,将序列转换成整数再哈希
	int t = 0;
	for(int i = 0;i < 9; ++i)
		t = t * 10 + st[s][i];
	return t % MAX;
}
int Insert(int s){//哈希表判断是否有重复
	int k = Hash(s);
	int v = head[k];
	while(v){
		if(memcmp(st[s],st[v],sizeof(st[s])) == 0)
			return 0;
		v = nnext[v];
	}
	nnext[s] = head[k];
	head[k] = s;
	return 1;
}
int bfs(){//八数码问题就是把状态作为各个节点然后使用宽搜获得最短路径,此题答案不唯一。
	int i;
	memset(head,0,sizeof(head));
	memset(dist,0,sizeof(dist));//初始化步长数组(紫书)
	int front = 1,rear = 2;
	while(rear > front){
		int s = front;
		if(memcmp(st[s],goal,sizeof(goal)) == 0)
			return s;
		for(i = 0;i < 9; ++i)
			if(!st[s][i])
				break;
		int z = i;
		int x = z / 3,y = z % 3;
		for(int i = 0;i < 4; ++i){
			int nx = x + d[i][0];
			int ny = y + d[i][1];
			int nz = nx * 3 + ny;
			if(nx >= 0 && nx < 3 && ny >= 0 && ny < 3){
				memcpy(st[rear],st[s],sizeof(st[s]));
				st[rear][z] = st[s][nz];
				st[rear][nz] = st[s][z];
				dist[rear] = dist[s] + 1;
				fa[rear] = s;//记录父节点,便于输出路径
				if(Insert(rear)){
					rear++;	
				}
			}	
		}
		++front;
	}
	return 0;
}
char step(int s){//获得移动方式
	int t = fa[s];
	if(!fa[s])
		return '0';
	int i;
	for(i = 0;i < 9; ++i){
		if(!st[s][i])
			break;
	}
	int x = i / 3,y = i % 3;
	for(i = 0;i < 9; ++i){
		if(!st[t][i])
			break;
	}
	int nx = i / 3,ny = i % 3;
	int dx = x - nx,dy = y - ny;
	if(dx == 0 && dy == -1)
		return 'l';
	if(dx == -1 && dy == 0)
		return 'u';
	if(dx == 0 && dy == 1)
		return 'r';
	if(dx == 1 && dy == 0)
		return 'd';
	
}
int main(){
	int i;
	char c;
	for(i = 0;i < 9; ++i){
		cin >> c;
		if(c == 'x')
			c = '0';
		st[1][i] = c - '0';
	}
	memset(fa,0,sizeof(fa));
	int ans = bfs();
	int cnt = 0;
	char t,temp[50];
	if(ans){
		while(1){
			t = step(ans);
			if(t == '0')
				break;
			temp[cnt++] = t;
			ans = fa[ans];
		}
		for(i = cnt - 1;i >= 0; --i)
			printf("%c",temp[i]);
		printf("\n");
	}
	else
		printf("unsolvable\n");
	return 0;
}

百练的G++编译器实在是太智能了,next也不能作为数组名。

发布了53 篇原创文章 · 获赞 0 · 访问量 719

猜你喜欢

转载自blog.csdn.net/weixin_38894974/article/details/104555541