康拓展开

可以用于将排列hash为第多少个排列
分解为x=an(n-1)!+ai(i-1)!+a1*0!
ai为还未出现的第几大(从0开始)
逆康拓可以用于找第多少个排列,获取不断对阶乘辗转相除的余数作为排列中的第几大
八数码,astar
h为预估为总的离自己曼哈顿距离和
利用优先队列对g+h排序
利用康托展开hash或者直接用map保存状态
一开始利用去掉空块的逆序数的移动一次逆序数改变为偶数判断是否有解
左右移动不变逆序数不变,上下移动为移动到相邻两个前后
逆序数相邻移动改变逆序数为1两次同向移动为2

#include <bits/stdc++.h>
using namespace std;
const int N = 10;
int d[N][N];
int a[N];
map<int,int> p;
void Init() {
	for (int i = 0;i < 3;i++)
		for (int j = 0;j < 3;j++) {
			for (int x = 0;x < 3;x++) {
				for (int y = 0;y < 3;y++) {
					d[i * 3 + j+1][x * 3 + y+1] = abs(x - i) + abs(y - j);
				}
			}
		}
}
int CalDis(int state){
	int s = 0;
	int k = 0;
	while(state){
		s += d[9 - k][state % 10];
		state /= 10;
		k++;
	}
	return s;
}
map<int,int> mp;
int GetState(int *a) {
	int s = 0;
	for (int i = 1;i <= 9;i++) {
		s = s * 10 + a[i];
	}
	return s;
}
bool GetNState(int state,int& nstate,int x, int y, int nx, int ny) {
	int k1 = 8-(x * 3 + y-4);
	int k2 = 8-(nx * 3 + ny-4);
	int x1 = 1, x2 = 1, d1 = 0, d2 = 0;
	for (int i = 0;i <= max(k1, k2);i++) {
		if (i == k1) {
			d1 = state / x1 % 10;
		}
		if (i == k2) {
			d2 = state / x2 % 10;
		}
		if (i < k1) {
			x1 *= 10;
		}
		if (i < k2) {
			x2 *= 10;
		}
	}
	nstate = state - (x1*d1 + x2*d2) + (x1*d2 + x2*d1);
	return true;
}
bool GetXY(int state, int& x, int& y) {
	int k=8;
	while (state%10!=9) {
		state /= 10;
		k--;
	}
	x = k / 3+1;
	y = k % 3+1;
	return true;
}
int dx[] = { 1,0,-1,0 };
int dy[] = { 0,1,0,-1 };
bool ok(int i, int j) {
	if (i <= 0 || j <= 0 || i>3 || j>3)return false;
	return true;
}
struct Node {
	int state, edis;
	bool operator <(const Node& rhs)const {
		return edis > rhs.edis;
	}
};
void Astar(int state) {
	int x, y;
	priority_queue<Node>q;
	q.push(Node{ state,CalDis(state) });
	while (!q.empty()) {
		Node node = q.top();q.pop();
		int state = node.state;
		if (state == 123456789) {
			return;
		}
		GetXY(state, x, y);
		for (int i = 0;i < 4;i++) {
			int nx = x + dx[i];
			int ny = y + dy[i];
			if (ok(nx, ny)) {
				int nstate;
				GetNState(state, nstate, x, y, nx, ny);
				if (!mp.count(nstate)) {
					mp[nstate] = mp[state] + 1;
					q.push(Node{ nstate,mp[nstate]+CalDis(nstate) });
					p[nstate] = state;
				}
				else {
					if (mp[nstate] > mp[state] + 1) {
						mp[nstate] = mp[state] + 1;
						q.push(Node{ nstate,mp[nstate]+CalDis(nstate) });
						p[nstate] = state;
					}
				}

			}
		}
	}
}
char CalMove(int state, int nstate) {
	int x, y, nx, ny;
	GetXY(state, x, y);
	GetXY(nstate, nx, ny);
	if (x < nx) { return 'd'; }
	if (x > nx) { return 'u'; }
	if (y < ny) { return 'r'; }
	if (y > ny) { return 'l'; }
}
void print(int state,int nstate) {
	if (p[state] != -1)
		print(p[state],state);
	printf("%c",CalMove(state, nstate));
}
bool CanSolve(int state) {
	int s = 0;
	int b[10] = { 0 };
	while (state) {
		int x = state % 10;
		if (x != 9) {
			s += (8 - state % 10) - b[state % 10];
			for (int i = 1;i < state % 10;i++)
				b[i]++;
		}
		state /= 10;
	}
	return (s % 2==0);
}
void solve() {
	int state = GetState(a);
	if (!CanSolve(state)) {
		printf("unsolvable
");
		return;
	}
	p[state] = -1;
	mp[state] = 0;
	Astar(state);
	if(p[123456789]!=-1)
		print(p[123456789],123456789);
	printf("
");
}
int main()
{
	Init();
	int b, i, j, s = 1, sum = 0;
	char x[5];
	while (scanf("%s",x)!=EOF)
	{
		p.clear();
		mp.clear();
		a[1] = x[0] - '0';
		for (int i = 2;i <= 9;i++) {
			scanf("%s", x);
			a[i] = x[0] - '0';
		}
		for (int i = 1;i <= 9;i++) {
			if (a[i] == 'x' - '0')
				a[i] = 9;
		}
		solve();
	}
}
原文地址:https://www.cnblogs.com/HaibaraAi/p/5042952.html