典型的bfs, 第一个是自己写的没有做任何优化,需要8^8的空间保存状态
后来看了别人解题报告,学会了康托展开,全排列压缩,只需要8!空间
#include <iostream> #include <string> #include <queue> #include <memory.h> using namespace std; struct my_status { int a[2][4]; string path; my_status(){} my_status(int a[2][4]) { for (int i = 0; i < 2; i++) for (int j = 0; j < 4; j++) this->a[i][j] = a[i][j]; path = ""; } my_status& operator=(const my_status& item) { for (int i = 0; i < 2; i++) for (int j = 0; j < 4; j++) a[i][j] = item.a[i][j]; path = item.path; return *this; } bool operator== (const my_status& item) { for (int i = 0; i < 2; i++) for (int j = 0; j < 4; j++) if (a[i][j] != item.a[i][j]) return false; return true; } }; bool isvisit[8][8][8][8][8][8][8][8]; int max_step; int goal_status[2][4]; int inite_statue[2][4] = {{1,2,3,4}, {8,7,6,5}}; my_status do_operate(int, const my_status&); void bfs(); int main() { while (cin >> max_step && max_step != -1) { memset(isvisit, false, sizeof(isvisit)); for (int i = 0; i < 2; i++) for (int j = 0; j < 4; j++) cin >> goal_status[i][j]; bfs(); } return 0; } void bfs() { my_status p,next_status; queue<my_status> Q; char c; Q.push(inite_statue); while (!Q.empty()) { p = Q.front(); Q.pop(); if (p.path.size() > max_step) { cout << "-1" << endl; return; } if (p == goal_status) { cout << p.path.size() << " " << p.path << endl; return; } for (int i = 0; i < 3; i++) { next_status = do_operate(i, p); c = 'A'+i; next_status.path = p.path + c; if (!isvisit[next_status.a[0][0]-1][next_status.a[0][1]-1][next_status.a[0][2]-1][next_status.a[0][3]-1][next_status.a[1][0]-1][next_status.a[1][1]-1][next_status.a[1][2]-1][next_status.a[1][3]-1]) { isvisit[next_status.a[0][0]-1][next_status.a[0][1]-1][next_status.a[0][2]-1][next_status.a[0][3]-1][next_status.a[1][0]-1][next_status.a[1][1]-1][next_status.a[1][2]-1][next_status.a[1][3]-1] = true; Q.push(next_status); } } } } my_status do_operate(int mode, const my_status& p) { my_status tmp; switch (mode) { case 0: for (int i = 0; i < 4; i++) { tmp.a[0][i] = p.a[1][i]; tmp.a[1][i] = p.a[0][i]; } break; case 1: for (int i = 1; i < 4; i++) { tmp.a[0][i] = p.a[0][i-1]; tmp.a[1][i] = p.a[1][i-1]; } tmp.a[0][0] = p.a[0][3]; tmp.a[1][0] = p.a[1][3]; break; case 2: tmp = p; tmp.a[0][1] = p.a[1][1]; tmp.a[0][2] = p.a[0][1]; tmp.a[1][1] = p.a[1][2]; tmp.a[1][2] = p.a[0][2]; break; } return tmp; }
康托展开
#include <iostream> #include <string> #include <queue> #include <memory.h> using namespace std; struct my_status { int a; string path; }; int fact[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320}; //8!的阶乘表 bool isvisit[50000]; int max_step; int goal_status; int inite_statue = 12348765; int do_operate(int, int); //康托状态压缩 //把需要8^8的储存空间压缩成只需8!空间 //只有8!有效 int encode(int n) { int tmp[8]; int cnt, sum; for (int i = 7; i >= 0; i--) { tmp[i] = n%10; n /= 10; } for (int i = 0; i < 7; i++) { cnt = 0; for (int j = i+1; j < 8; j++) if (tmp[i] > tmp[j]) cnt++; n += fact[8-i-1] * cnt; } return n; } void bfs(); int main() { int tmp[8]; while (cin >> max_step && max_step != -1) { memset(isvisit, false, sizeof(isvisit)); for (int i = 0; i < 8; i++) cin >> tmp[i]; goal_status = tmp[0]*1e7 +tmp[1]*1e6 + tmp[2]*1e5 + tmp[3]*1e4 + tmp[4]*1e3 + tmp[5]*1e2 + tmp[6]*1e1 + tmp[7]; bfs(); } return 0; } void bfs() { my_status p,next_status; p.a = inite_statue; p.path = ""; queue<my_status> Q; char c; Q.push(p); while (!Q.empty()) { p = Q.front(); Q.pop(); if (p.path.size() > max_step) { cout << "-1" << endl; return; } if (p.a == goal_status) { cout << p.path.size() << " " << p.path << endl; return; } for (int i = 0; i < 3; i++) { next_status.a = do_operate(i, p.a); c = 'A'+i; next_status.path = p.path + c; if (!isvisit[encode(next_status.a)]) { isvisit[encode(next_status.a)] = true; Q.push(next_status); } } } } int do_operate(int mode, int number) { int tmp = number; switch (mode) { case 0: //操作A,上下行交换 tmp = number/1000%10*1e7 + number/100%10*1e6 + number/10%10*1e5 + number%10*1e4 + number/(10000000)%10*1e3 + number/1000000%10*1e2 + number/100000%10*10 + number/10000%10; break; case 1: //操作B,每行向后移动一位 tmp = number/10000%10*1e7 + number/10000000%10*1e6 + number/1000000%10*1e5 + number/100000%10*1e4 + number%10*1e3 + number/1000%10*1e2 + number/100%10*10 +number/10%10; break; case 2: //操作C,旋转 tmp = number/10000000%10*1e7 + number/100%10*1e6 + number/1000000%10*1e5 + number/10000%10*1e4 + number/1000%10*1e3 + number/10%10*1e2 + number/100000%10*10 + number%10; break; } return tmp; }