【康托展开+状压BFS】poj1077 Eight(八数码问题)
来源:互联网 发布:linux中如何创建用户 编辑:程序博客网 时间:2024/05/21 10:46
这是经典的“八数码问题”。解法有很多,这里用的是状压BFS。
不过涉及一个有趣的东西:康托展开。
显然,我们可以把'x'当做0,这样每一个棋盘的状态对应的就是一个0~8的一个排列。
然后就是怎么压缩这个排列状态的问题。康托展开和其逆展开对此作了解答。
具体不难,就不介绍了。但是技不压身,我特地学习了一下,然后自己写了一个模板。就是一种编码方式,包括编码和解码,以后就可以直接用了。
#include <cstdio>#include <cstring>#include <queue>#include <vector>#include <map>#include <stack>#include <algorithm>using namespace std;/*************************Cantor expansion***************************/const int CACNTOR_MAX = 13;int fac[CACNTOR_MAX] = {1, 1, 2, 6, 24, 120,720, 5040, 40320, 362880,3628800, 39916800, 479001600}; //fac list, fac[i] = i!, fac[max] = fac[12] = 479 001 600//put x = a[0] * 1! + ... + a[bit-1] * bit! and put into array a[]//0 <= a[i] <= i+1//x count from 0int decode(int a[], int bit, int x) {bool tmp[CACNTOR_MAX] = {0};//array[1,2,...bit]//if U want to get [0, 1, ... , bit - 1]//change//a[i] = j//to: a[i] = j - 1;int res;for (int i = 0; i < bit; ++i) {a[i] = x / fac[bit - i - 1];x %= fac[bit - i - 1];int j = 1;for (int l = 0; l <= a[i]; ++j)if (!tmp[j]) ++l;tmp[--j] = true;a[i] = j - 1;if (j == 1) res = i;}return res;}//use [0, 1, 2, ..., bit-1] or [1, 2, ..., bit]//it all works.int encode(int a[], int bit) {int s = 0;for (int i = 0; i < bit; ++i) {int c = 0;for (int j = i + 1; j < bit; ++j) {c += a[j] < a[i];}s += c * fac[bit-i-1];}return s;}/********************************************************************/const int MAX = 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 + 7;char move[MAX];int father[MAX];bool vis[MAX];void debug(int status) {int a[10];decode(a, 9, status);for (int i = 0; i < 9; ++i) {printf("%d ", a[i]);}puts("");}int BFS(int s, int t) {memset(vis, false, sizeof(vis));memset(father, -1, sizeof(father));queue<int> Q;Q.push(s);vis[s] = true;int now, next, a[9];while (!Q.empty()) {now = Q.front();Q.pop();if (now == t) return t;int pos = decode(a, 9, now);//u: upif (pos > 2) {swap(a[pos], a[pos - 3]);next = encode(a, 9);if (!vis[next]) {vis[next] = true;father[next] = now;move[next] = 'u';Q.push(next);//debug(next);}swap(a[pos], a[pos - 3]);}//dif (pos < 6) {swap(a[pos], a[pos + 3]);next = encode(a, 9);if (!vis[next]) {vis[next] = true;father[next] = now;move[next] = 'd';Q.push(next);//debug(next);}swap(a[pos], a[pos + 3]);}//lif (pos % 3) {swap(a[pos], a[pos - 1]);next = encode(a, 9);if (!vis[next]) {vis[next] = true;father[next] = now;move[next] = 'l';Q.push(next);//debug(next);}swap(a[pos], a[pos - 1]);}//rif ((pos % 3) < 2) {swap(a[pos], a[pos + 1]);next = encode(a, 9);if (!vis[next]) {vis[next] = true;father[next] = now;move[next] = 'r';Q.push(next);//debug(next);}swap(a[pos], a[pos + 1]);}}return -1;}int main() {int a[10];char ch;while (~scanf(" %c", &ch)) {a[0] = ch == 'x' ? 0 : ch - '0';for (int i = 1; i < 9; ++i) {scanf(" %c", &ch);a[i] = ch == 'x' ? 0 : ch - '0';}int s = encode(a, 9);for (int i = 0; i < 9; ++i) {a[i] = (i + 1) % 9;}int t = encode(a, 9);int ret = BFS(s, t);if (ret == -1) {puts("unsolvable");continue;}//printf("s = %d, t = %d\n", s, t);int p = t;stack<char> S;while (!S.empty()) S.pop();while (p != -1) {S.push(move[p]);p = father[p];}S.pop();while (!S.empty()) {putchar(S.top());S.pop();}putchar('\n');}return 0;}
0 0
- 【康托展开+状压BFS】poj1077 Eight(八数码问题)
- POJ1077 HDU1043 Eight 八数码 (A*+康托展开)
- POJ 1077 Eight 八数码问题[康托展开 + BFS]
- [POJ]1077 Eight 八数码:康托展开+BFS
- POJ1077 HDU1043 Eight 八数码第四境界 双向广搜 康托展开 逆康托
- POJ1077&HDU1043 Eight 八数码第八境界 IDA* hash 康托展开 奇偶剪枝
- hdu 1043 /poj 1077 Eight(经典八数码问题,BFS+康托展开)
- POJ1077、HDU1043 Eight 八数码问题:双向BFS、A*
- POJ1077&HDU1043 Eight 八数码第七境界 AStar hash 康托展开 最小堆优化 奇偶剪枝
- HDU 1043 Eight (BFS·八数码·康托展开)
- hdu 1043/poj 1077 Eight (八数码 经典搜索题 bfs + 康托展开)
- 【POJ1077】Eight-A*+康托展开
- poj1077 hdu1043 Eight 八数码问题
- 康托展开求八数码问题
- 康托展开(八数码问题)
- HDU 1043 Eight ((八数码问题)逆向BFS + 康托定理判重)
- 八数码问题,bfs,hash,康托
- POJ1077八数码问题哈希,bfs
- 开博客了
- javascript 获取滚动条高度+常用js页面宽度与高度
- 负数与二进制换转方法
- 支持中文文本的数据挖掘平台开源项目PyMining发布
- CSS 颜色十六进制值
- 【康托展开+状压BFS】poj1077 Eight(八数码问题)
- jquery操作select(取值,设置选中)
- parted创建GPT分区(支持2T以上硬盘)
- mysql_query函数中卡死
- MatLab 2014a编译jar包时mcc无法使用的问题
- handler.post(runnable)
- VS2008调试快捷键
- oracle 多表查询
- vs2010编译错误:#error 指令: Please use the /MD switch for _AFXDLL