Luogu2578 [ZJOI2005]九数码游戏
Posted xcysblog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu2578 [ZJOI2005]九数码游戏相关的知识,希望对你有一定的参考价值。
状态数不是很多,直接 bfs
输出方案就记录 pre 状态即可
但是问题在于存状态
可行的一些方案是:哈希/map,康托展开
于是就学了一波康托展开
用康托展开的地方的地方感觉不会很多,毕竟要 n^2 算
大概意思就是给一个排列 hash
计算出来的就是这个排列在所有 n 的排列中的排名
计算方式就从这里看吧
不过代码实现略有不同
大体思路是差不多的
逆展开就是当前这一位上的数字的排名
从可用数字中选出这个排名的数,并把它从可用集合中删除
代码:
#include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cctype> #include<cstdio> #include<queue> using namespace std; const int MAXN = 11, MAXSIZ = 5; struct INFO{ int stt[MAXN], stp, ex; }bgn; int ans, top; int pi[MAXN], out[MAXN], tmp[MAXN]; int stp[363000], pre[363000], stk[363000]; bool getans, vis[10]; queue<INFO> q; inline void turnmid(int *stt) { register int tmp = stt[4]; stt[4] = stt[6]; stt[6] = stt[5]; stt[5] = tmp; return; } inline void turnroll(int *stt) { register int tmp = stt[1]; stt[1] = stt[4]; stt[4] = stt[7]; stt[7] = stt[8]; stt[8] = stt[9]; stt[9] = stt[6]; stt[6] = stt[3]; stt[3] = stt[2]; stt[2] = tmp; return; } inline int expnd(int *dst) { register int res = 0, tmp = 0; for(int i = 1; i <= 9; ++i) { tmp = 0; for(int j = i + 1; j <= 9; ++j) tmp += (dst[j] < dst[i]); res += tmp * pi[9 - i]; } return res; } inline void antiex(int ex) { register int siz = 8, val = 0; for(int i = 0; i < 9; ++i) tmp[i] = i; for(int i = 1; i <= 9; ++i) { val = (ex / pi[9 - i]); ex %= pi[9 - i]; out[i] = tmp[val]; for(int j = val; j < siz; ++j) tmp[j] = tmp[j + 1]; --siz; } return; } inline void write(int ex) { getans = true; while(~ex) { stk[++top] = ex; //printf("ex = %d ", ex); ex = pre[ex]; } while(top) { antiex(stk[top--]); for(int i = 1; i <= 9; ++i) printf("%d%c", out[i], " "[i % 3 == 0]); putchar(‘ ‘); } return; } inline void bfs() { bgn.ex = expnd(bgn.stt); bgn.stp = 0; pre[bgn.ex] = -1; stp[bgn.ex] = 0; q.push(bgn); INFO cur, d1, d2; while(!q.empty()) { cur = q.front(); q.pop(); //printf("now state : "); //for(int i = 1; i <= 9; ++i) // printf("%d%c", cur.stt[i], " "[i % 3 == 0]); ++cur.stp; d1 = cur; d2 = cur; turnroll(d1.stt); turnmid(d2.stt); d1.ex = expnd(d1.stt); d2.ex = expnd(d2.stt); if(stp[d1.ex] > d1.stp) { stp[d1.ex] = d1.stp; pre[d1.ex] = cur.ex; q.push(d1); } if(stp[d2.ex] > d2.stp) { stp[d2.ex] = d2.stp; pre[d2.ex] = cur.ex; q.push(d2); } if(d1.ex == ans) { printf("%d ", d1.stp); write(d1.ex); return; } if(d2.ex == ans) { printf("%d ", d2.stp); write(d2.ex); return; } } return; } int main() { memset(stp, 0x3f, sizeof(stp)); pi[0] = pi[1] = 1; for(int i = 0 ;i < 363000; ++i) pre[i] = -1; for(int i = 2; i <= 9; ++i) pi[i] = pi[i - 1] * i; for(int i = 1; i <= 9; ++i) bgn.stt[i] = i - 1; ans = expnd(bgn.stt); for(int i = 1; i <= 9; ++i) scanf("%d", &bgn.stt[i]); bfs(); if(!getans) puts("UNSOLVABLE"); return 0; }
以上是关于Luogu2578 [ZJOI2005]九数码游戏的主要内容,如果未能解决你的问题,请参考以下文章