Luogu2578 [ZJOI2005]九數碼遊戲
阿新 • • 發佈:2018-10-11
str 代碼 oid you inf 不同 ash .html for
狀態數不是很多,直接 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\n", ex); ex = pre[ex]; } while(top) { antiex(stk[top--]); for(int i = 1; i <= 9; ++i) printf("%d%c", out[i], " \n"[i % 3 == 0]); putchar(‘\n‘); } 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 : \n"); //for(int i = 1; i <= 9; ++i) // printf("%d%c", cur.stt[i], " \n"[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\n", d1.stp); write(d1.ex); return; } if(d2.ex == ans) { printf("%d\n", 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]九數碼遊戲