八数码

原题:八数码

在八数码中,估价函数就是所有数字在state中的位置与目标位置end中的位置的曼哈顿距离之和,即:

f(state)=i=18(|state_xiend_xi|+|state_yiend_yi|)

对于八数码问题有个结论:

八数码逆序对必须是偶数才有解,因为每次左右移动都不会改变逆序对的个数,只有上下移动才会增加或者减少两个逆序对,所以如果逆序对是奇数那我们无论如何都无解。


#include <bits/stdc++.h>

using namespace std;

typedef pair<int, string> PIS;

int f(string str) {
	int res = 0;
	for (int i = 0; i < str.size(); i++) {
	    if (str[i] != 'x') {
	        int t = str[i] - '1';
		    res += abs(i / 3 - t / 3) + abs(i % 3 - t % 3);   
	    }
	}
	
	return res;
}

string bfs(string start) {
	int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
	string end = "12345678x";
	char op[] = "urdl";
	
	priority_queue<PIS, vector<PIS>, greater<PIS>> heap;
	unordered_map<string, int> dist;
	unordered_map<string, pair<char, string>> prev;
	
	heap.push({0 + f(start), start});
	dist[start] = 0;
	
	while (heap.size()) {
		auto t = heap.top();
		heap.pop();
		
		string state = t.second;
		
		if (state == end) break; 
		
		int x, y;
		for (int i = 0; i < state.size(); i++) {
			if (state[i] == 'x') {
				x = i / 3, y = i % 3;
				break;
			}
		}
		
		string source = state;
		for (int i = 0; i < 4; i++) {
			int a =  x + dx[i], b = y + dy[i];
			if (a >= 0 && a < 3 && b >= 0 && b < 3) {
				swap(state[x * 3 + y], state[a * 3 + b]);
				if (!dist.count(state) || dist[state] > dist[source] + 1) {
					dist[state] = dist[source] + 1;
					prev[state]	= {op[i], source};
					heap.push({dist[state] + f(state), state});
				}
				swap(state[x * 3 + y], state[a * 3 + b]);
			}
		}
	}
	
	string res = "";
	
	while (end != start) {
		res += prev[end].first;
		end = prev[end].second;
	}

	reverse(res.begin(), res.end());
	
	return res;
}

int main() {
	string start, str;
	char c;
	while (cin >> c) {
		start += c;
		if (c != 'x') str += c;
	}
	
	int cnt = 0;
	for (int i = 0; i < str.size(); i++) {
		for (int j = i; j < str.size(); j++) {
			if (str[i] - '0' > str[j] - '0') cnt++; 
		}
	}
	
	if (cnt & 1) puts("unsolvable");
	else {
		cout << bfs(start) << endl;	
	}
	
    return 0;
}
posted @   Xxaj5  阅读(344)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示