判断无解的情况(写完七种境界才发现有直接判断无解的方法):
一个状态表示成一维的形式,求出除0之外所有数字的逆序数之和,也就是每个数字前面比它大的数字的个数的和,称为这个状态的逆序。
若两个状态的逆序奇偶性相同,则可相互到达,否则不可相互到达。
POJ提交记录(从下往上依次为第1,2,3,4,5,6,7,8境界):
本文转自:http://www.cnblogs.com/zufezzt/p/5659276.html
HDU提交记录(从下往上依次为第1,2,3,4,5,6,7,8境界):
PS:因为HDU是多组测试数据,所以一般POJ上要100ms以上才能AC的方法,在HDU上是无法通过的(境界3除外)。
境界一、 暴力广搜+STL (HDU 内存超限,POJ 时间超限)
map存路径,set判重,string存状态,毫无疑问,炸了。
#include<cstdio> #include<cstring> #include<string> #include<cmath> #include<vector> #include<queue> #include<set> #include<map> #include<algorithm> #include<iostream> using namespace std; char input[1000]; int dir[4][2] = { { -1,0 },{ 1,0 },{ 0,-1 },{ 0,1 } }; string d = "durl"; set<string>f; map<string, string>m; int sz = 0; struct node { string s; string path; int pos; node() {} node(string str, string pa, int Pos) { s = str; path = pa; pos = Pos; } }; bool g(int a, int b) { if (a >= 0 && a <= 2 && b >= 0 && b <= 2) return 1; return 0; } void pre() { queue<node>q; q.push(node("12345678x", "", 8)); m["12345678x"] = ""; f.insert("12345678x"); while (!q.empty()) { node h = q.front(); q.pop(); int a = h.pos / 3, b = h.pos % 3; for (int i = 0; i<4; i++) { int x = a + dir[i][0], y = b + dir[i][1]; if (!g(x, y)) continue; int pos = 3 * x + y; swap(h.s[h.pos], h.s[pos]); if (f.find(h.s) != f.end()) { swap(h.s[h.pos], h.s[pos]); continue; } q.push(node(h.s, d[i] + h.path, pos)); f.insert(h.s); m[h.s] = d[i] + h.path; swap(h.s[h.pos], h.s[pos]); } } } int main() { pre(); while(~scanf("%s",input)) { string v=""; v = v + input[0]; for (int i = 1; i <= 8; i++) { scanf("%s", input); v = v + input[0]; } if (m[v] == "") cout << "unsolvable" << endl; else cout << m[v] << endl; } return 0; }
境界二、广搜+哈希(POJ 453ms)
利用康托展开对状态进行hash,hash值对应0--(9!-1),因此可以开数组判重,路径的记录可以记录到达某状态的最后一步操作是什么与父节点是什么。
从输入的状态开始进行BFS,直到找到最终状态。
时间: 2024-10-13 16:21:53