反向BFS+康托展开Eight HDU - 1043

Posted streamazure

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反向BFS+康托展开Eight HDU - 1043相关的知识,希望对你有一定的参考价值。

Eight

题意:八数码问题

思路:反向BFS+康托展开

const int maxn = 362885;

const int FAC[] = { 1,1,2,6,24,120,720,5040,40320,362880,3628800 };

int cantor(int* a) {//算出全排列对应的哈希值
	int x = 0;
	for (int i = 0; i < 9; i++) {
		int smaller = 0;
		for (int j = i + 1; j < 9; j++) {
			if (a[j] < a[i]) smaller++;
		}
		x += FAC[9 - i - 1] * smaller;
	}
	return x;
	//注意全排列数组a是从零开始的
}


void decantor(int x, int*ans) {//x哈希值,n数字个数,a算出的全排列

	vector<int> v;
	for (int i = 1; i <= 9; i++) v.push_back(i);
	for (int i = 0; i < 9; i++) {
		int r;
		r = x / FAC[9 - i - 1];
		x = x % FAC[9 - i - 1];
		sort(v.begin(), v.end());
		ans[i] = v[r];
		v.erase(v.begin() + r);
	}
	//注意算出的全排列数组ans是从0开始的

}

//描述每个状态需要有以下信息
struct node {
	int hash;
	int pos;
	int pre;
};

string path[maxn];//下标是一个状态的哈希值,表示从该状态到达目标状态的路径
bool vis[maxn];
int dx[] = { 1,-1,0,0 };
int dy[] = { 0,0,-1,1 };
char dir_op[5] = "udrl";
//反向bfs,所以路径记录和实际运算反着来,如空格坐标运算为下移一行时,路径记录为u

void bfs() {
	queue<node> q;

	node temp;
	int a[10];
	for (int i = 0; i < 9; i++) a[i] = i + 1;
	//反向bfs
	//故目标状态即起始状态,即123456789
	temp.hash = cantor(a);
	temp.pre = -1;
	temp.pos = 8;//从0起计,代表空格的9在状态数组中下标为8
	path[temp.hash] = "";

	q.push(temp);
	vis[temp.hash] = 1;
	while (!q.empty()) {
		temp = q.front();
		q.pop();
		int sx = temp.pos / 3;
		int sy = temp.pos % 3;
		decantor(temp.hash, a);
		//逆运算得到该节点状态数组
		for (int i = 0; i < 4; i++) {
			int nx = sx + dx[i];
			int ny = sy + dy[i];
			int npos = nx * 3 + ny;
			//换位后空格所在的新位置
			if (nx < 0 || ny < 0 || nx>2 || ny>2) continue;
			swap(a[temp.pos], a[npos]);
			//换位置后的状态数组再算出哈希值
			int nval = cantor(a);
			if (vis[nval]) {
				swap(a[temp.pos], a[npos]);
				//如果该状态已经遇到过,复原回去,继续尝试其他换位
				continue;
			}
			node t;
			t.hash = nval;
			t.pos = npos;
			t.pre = temp.hash;
			//记录该状态的上一状态的哈希值
			path[nval] = dir_op[i] + path[temp.hash];
			//注意因为是反向bfs,移动记录的顺序也是反着的
			//如从某状态经udlr到达状态123456789
			//而代码从123456789开始运算,是经lrud到达该状态的
			//其中“方向相反”已在定义dir_op时完成,只要将新的操作记在之前所有操作的最前面即可

			q.push(t);
			vis[nval] = 1;
			//新状态入队并记录
			swap(a[temp.pos], a[npos]);
			//复原回去,继续尝试其他换位
		}
	}
	
}

int main()
{
	//ios::sync_with_stdio(false);
	//int t; cin >> t; while (t--){
	string s;
	memset(vis, 0, sizeof(vis));
	bfs();
	//bfs一次解决所有多组样例
	int a[10];
	while (getline(cin, s)) {
		int j = 0;
		for (int i = 0; i < s.size(); i++) {
			if (s[i] == ‘x‘) a[j++] = 9;
			else if (isdigit(s[i])) a[j++] = s[i] - ‘0‘;
		}
		int ans = cantor(a);
		if (vis[ans]) {
			cout << path[ans] << endl;
		}
		else cout << "unsolvable" << endl;
	}
	return 0;
}

以上是关于反向BFS+康托展开Eight HDU - 1043的主要内容,如果未能解决你的问题,请参考以下文章

HDU - 1043Eight(反向bfs+康托展开)

hdu 1043 Eight(康托展开 + BFS)

HDU 1043 Eight(双向BFS+康托展开)

POJ 1077 Eight(bfs+康托展开)

POJ 1077 Eight(康托展开+BFS)

HDU 1043 Eight(哈希 + BFS)