杭电OJ 1067(C++)

本文介绍了一种使用广度优先搜索(BFS)算法解决八数码拼图问题的方法。通过将拼图状态转换为字符串并利用哈希函数,实现对状态的快速查找,避免重复搜索。文章详细解释了如何构建节点结构、状态转换以及哈希值计算,并最终找到从初始状态到目标状态的最短路径。
#include <iostream>
#include <algorithm>
#include <string>
#include <queue>
using namespace std;

int aim[32] =
{
	11, 12, 13, 14, 15, 16, 17, 0,
	21, 22, 23, 24, 25, 26, 27, 0,
	31, 32, 33, 34, 35, 36, 37, 0,
	41, 42, 43, 44, 45, 46, 47, 0
}; //目标状态
char mp[4][8]; //输入
bool book[1000008]; //访问状态

struct point
{
	int r; //行数
	int c; //列数
};
struct node //一个数组状态
{
	point num[48]; //全部格子
	point zero[4]; //空格子
	string mp; //整个数组转换为的字符串
	int step; //步数
}st;

int Hash(string s) //求字符串的哈希值
{
	long long sum = 0;
	for (int i = 0; i < 32; i++)
		sum = sum * 2 + s[i]; //将字符串转换为一个较大且不重复的整数(方法不唯一)
	return sum % 1000007; //哈希值(方法不唯一)
}

int bfs()
{
	queue<node> q;
	while (!q.empty()) //清空队列
		q.pop();
	st.step = 0; 
	q.push(st);
	string s = ""; //目标状态字符串
	for (int i = 0; i < 32; i++)
		s.push_back(aim[i]);
	int END = Hash(s); //目标哈希值

	while (!q.empty())
	{
		node temp, next;
		temp = q.front();
		q.pop();
		if (Hash(temp.mp) == END) //达到目标状态
			return temp.step;
	
		for (int i = 0; i < 4; i++) //四个空格子
		{
			next = temp;
			next.step++;
			point &a = next.zero[i];
			int m = a.r * 8 + a.c - 1; //此空格子在字符串中的左边一位
			int n = next.mp[m];
			if (n % 10 == 7 || n == 0) //空格子左边为尾数为7的数或空格子
				continue;
			n++; //应该填入该空格子中的数
			point &b = next.num[n];
			int o = b.r * 8 + b.c; //交换的数的位置
			m++; //空格子位置
			swap(next.mp[m], next.mp[o]); //空格子和对应的数交换(在字符串中)
			int x = Hash(next.mp);
			if (book[x])
				continue;
			book[x] = 1;
			swap(a, b); //空格子的坐标和对应数的坐标交换
			q.push(next);
		}
	}
	return -1;
}

void solve()
{
	int cnt = 0; //空格子数组索引
	st.mp.clear();
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 8; j++)
		{
			if (mp[i][j] == 0) //空格子
			{
				st.zero[cnt].r = i;
				st.zero[cnt++].c = j;
			}
			else //非空格子
			{
				st.num[mp[i][j]].r = i;
				st.num[mp[i][j]].c = j;
			}
			st.mp.push_back(mp[i][j]); //加入字符串(将整个数组状态转换为一个字符串)
		}
	}
	memset(book, 0, sizeof(book));
	book[Hash(st.mp)] = 1;
	cout << bfs() << endl;
}

int main()
{
	int t, x;
	cin >> t;
	while (t--)
	{
		memset(mp, 0, sizeof(mp));
		for (int i = 0; i < 4; i++)
		{
			for (int j = 1; j < 8; j++)
			{
				cin >> x;
				mp[i][j] = (char)x;
				if (x % 10 == 1) //将11,21,31,41换到对应的位置上
					swap(mp[i][j], mp[x/10 - 1][0]);
			}
		}
		solve();
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值