A.I. 八数码问题

最简单,最low的bfs暴力,凑合着看看吧

/*对有解性证明。
 引理:一个排列中任意两个元素对换,排列改变奇偶性
 设初始状态x1x2x3x4[]x5x6x7x8 ([]为空格)
 []有4种移动方式
 1.当[]左右移动,其排列相对次序不变,排列奇偶性不改变
 2.当[]上下移动,先考虑向下移动,初始状态改变为x1x2x3x4x7x5x6x8,相当于进行了2次相邻对换,排列奇偶性不变。向上同理。
 即证:不论如何移动,初始状态与目标状态的排列奇偶性应当一致,不然无解。
*/
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<ctime>
#include <unordered_map>
using namespace std;
string s0, sg;
int Is_odd(string s) {//排列的奇偶性
	int cnt = 0;
	for (int i = 0;i < s.length();++i) {//反正数据量小 O(n^2)怕啥。那不成还写归并排序吗。。我也不会呀
		for (int j = i + 1;j < s.length();++j) {
			if (s[i] != '0' && s[j] != '0' && s[i] - s[j] > 0) cnt++;
		}
	}
	return cnt % 2;//1
}
/*基本结构与判断---------------------------------*/
struct Node {//记录当前结点的状态,以及前驱结点
	string s;//283104765
	int pre;//
	Node() {}
	Node(string _s, int _pre) : s(_s), pre(_pre) {}
};
vector<Node>v;//Node v[100000]
int dis[5] = { -1,1,-3,3 };//四个方向,上下左右
bool Judge(int pos, int i) { //是否符合要求,要转换二维分析
	/*处在最左边不能左移,最右边不能右移*/
	/*280314765*/
	if (pos % 3 == 0 && i == 0 || pos % 3 == 2 && i == 1) return false;
	return pos + dis[i] > -1 && pos + dis[i] < 9;//[0,8]
}
/*-----------------------------------------------*/
/*输入输出*/
void Out(string s) {
	for (int i = 0;i < 3;++i) {
		cout << " - - -\n|";
		for (int j = i * 3;j < 3 * i + 3;++j) cout << s[j] << "|";
		cout << endl;
	}
	cout << endl;
}
void Print(Node ans) {
	if (ans.pre != -1)	Print(v[ans.pre]);
	Out(ans.s);
	return;
}
/*-----------------------------------------------*/
/*暴力广搜---------------------------------------*/
void Bfs() {
	/*这题类似于迷宫求解,保存路径。因此采用模拟队列的方法*/
	int front = 0, tail = 1;
	string tmp;
	unordered_map<string, bool>mp;
	v.push_back(Node(s0, -1));//将初始状态放入队列
	mp[s0] = 1;//每个节点只能拓展一次
	while (front < tail) {//队列全部找过
		if (v[front].s.compare(sg) == 0) {//123456780 123456780
			cout << "I got it!" << endl;
			Print(v[front]);
			return;
		}
		int pos = v[front].s.find("0");//找到空格的位置 s0 s1 s2 s3 s4 s5 
		for (int i = 0;i < 4;++i) {
			if (Judge(pos, i)) {
				tmp = v[front].s;//283104765->283014765
				swap(tmp[pos], tmp[pos + dis[i]]);//
				if (mp[tmp] == 0) {
					v.push_back(Node(tmp, front));//open
					mp[tmp] = 1;
					tail++;//v[1]=tmp,v[tail2]
				}
			}
		}
		front++;
	}
}
int main() {
	double s, e;
	/*freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);*/
	while(1) {
		cin >> s0;
		cin >> sg;
		if (Is_odd(s0) == Is_odd(sg)) Bfs();
		else  cout << "No solution!" << endl;
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值