【BHOJ ModricWang的星靈棋】狀壓 | BFS | 棋類 | trick : [0]陣列 | N
阿新 • • 發佈:2018-12-17
ModricWang的星靈棋
核心:狀壓 + BFS (後面還有一個小彩蛋哦)
時間限制: 1000 ms 記憶體限制: 65536 kb
總通過人數: 130 總提交人數: 156
題目描述
ModricWang上次出了兩個題,可是被校園網坑了,所以這一次準備出個一題更比四題強的題來維繫宇宙平衡。
星靈棋是一種流行於Aiur的棋類遊戲。ModricWang經常和他的表哥Artanis下星靈棋。
星靈棋規則如下:在一個4*4的棋盤上擺放了14顆棋子,其中有7顆白色棋子,7顆黑色棋子,有兩個空白地帶,任何一顆黑白棋子都可以向上下左右四個方向移動到相鄰的空格,這叫行棋一步,黑白雙方交替走棋,任意一方可以先走,如果某個時刻使得任意一種顏色的棋子形成四個一線(包括斜線),這樣的狀態為目標棋局,先達到目標棋局者贏。
由於ModricWang還有很多份解題報告沒有批,所以他根本不關心輸贏,只想趕緊把手裡這一盤下完走人。給定當前的棋局狀態,請你幫ModricWang算出最少還要多少步才能下完這盤棋。
輸入
只有一組評測資料。
一個4*4的初始棋局,黑棋子用B表示,白棋子用W表示,空格地帶用O表示。
保證輸入格式嚴格符合規範,總共只有4個連續的可見行,每行只有4個連續的可見字元。不存在前導空行或前導空格。
保證輸入資料完全符合規則,總共有7個B,7個W和2個O。
輸出
用最少的步數移動到目標棋局的步數。
輸入樣例
BWBO
WBWB
BWBW
WBWO
輸出樣例
5
分析
這道題
AC程式碼
#include <cstdio> #include <cstring> #include <unordered_set> #include <set> #define GC getchar enum { BLACK_CHESS = 1, BLACK_TURN = 1, WHITE_CHESS = 2, WHITE_TURN = 2, NO_CHESS = 0 }; #define RET return printf("%d", queue[tail].step), 0 #define UPDATE(r1, c1) \ if (now.r1>0 && now.getChess(now.r1-1, now.c1) == now.turn) \ { \ queue[tail] = now; \ --queue[tail].r1, ++queue[tail].step; \ if (queue[tail].putChess(queue[tail].r1, now.c1, NO_CHESS)) RET; \ if (queue[tail].putChess(now.r1, now.c1, now.turn)) RET; \ if (!VIS[now.turn-1].count(*queue[tail].uintValue)) \ { \ VIS[now.turn-1].insert(*queue[tail].uintValue); \ queue[tail++].turn = 3-now.turn; \ } \ } \ if (now.c1>0 && now.getChess(now.r1, now.c1-1) == now.turn) \ { \ queue[tail] = now; \ --queue[tail].c1, ++queue[tail].step; \ if (queue[tail].putChess(now.r1, queue[tail].c1, NO_CHESS)) RET; \ if (queue[tail].putChess(now.r1, now.c1, now.turn)) RET; \ if (!VIS[now.turn-1].count(*queue[tail].uintValue)) \ { \ VIS[now.turn-1].insert(*queue[tail].uintValue); \ queue[tail++].turn = 3-now.turn; \ } \ } \ if (now.r1<3 && now.getChess(now.r1+1, now.c1) == now.turn) \ { \ queue[tail] = now; \ ++queue[tail].r1, ++queue[tail].step; \ if (queue[tail].putChess(queue[tail].r1, now.c1, NO_CHESS)) RET; \ if (queue[tail].putChess(now.r1, now.c1, now.turn)) RET; \ if (!VIS[now.turn-1].count(*queue[tail].uintValue)) \ { \ VIS[now.turn-1].insert(*queue[tail].uintValue); \ queue[tail++].turn = 3-now.turn; \ } \ } \ if (now.c1<3 && now.getChess(now.r1, now.c1+1) == now.turn) \ { \ queue[tail] = now; \ ++queue[tail].c1, ++queue[tail].step; \ if (queue[tail].putChess(now.r1, queue[tail].c1, NO_CHESS)) RET; \ if (queue[tail].putChess(now.r1, now.c1, now.turn)) RET; \ if (!VIS[now.turn-1].count(*queue[tail].uintValue)) \ { \ VIS[now.turn-1].insert(*queue[tail].uintValue); \ queue[tail++].turn = 3-now.turn; \ } \ } typedef unsigned char uchar; std::unordered_set<unsigned int> _[5], *VIS=_+2; bool WIN[0xaa+1]; struct State { unsigned int uintValue[0]; uchar row[4], col[4]; uchar left, right; uchar r1, c1; uchar r2, c2; short step, turn; State(void) : step(0), turn(BLACK_TURN) { } inline bool putChess(const int r, const int c, uchar p) { uchar pl2r = p << 2*r, pl2c = p << 2*c, al2r = ~(3 << 2*r), al2c = ~(3 << 2*c); row[r] &= al2c, row[r] |= pl2c; if (WIN[row[r]]) return true; col[c] &= al2r, col[c] |= pl2r; if (WIN[col[c]]) return true; if (r == c) { left &= al2c, left |= pl2c; if (WIN[left]) return true; } if (r+c == 3) { right &= al2r, right |= pl2r; if (WIN[right]) return true; } return false; } inline uchar getChess(const int r, const int c) const { return (row[r] >> 2*c) & 3; } }; State queue[666666]; int main() { State src; memset(&src, 0, sizeof src); WIN[0xaa] = WIN[0x55] = true; for (int r=0, first_zero=1; r<4; ++r) { char str[123]; scanf("%s", str); for (int c=0; c<4; ++c) { switch(str[c]) { case 'B': if (src.putChess(r, c, BLACK_CHESS)) return puts("0"),0; break; case 'W': if (src.putChess(r, c, WHITE_CHESS)) return puts("0"),0; break; case 'O': if (first_zero) src.r2 = r, src.c2 = c, first_zero = 0; else src.r1 = r, src.c1 = c; break; } } } int head = 0, tail = 2; *queue = src; src.turn = WHITE_TURN; queue[1] = src; VIS[BLACK_TURN-1].insert(*src.uintValue); // 黑子的VIS VIS[WHITE_TURN-1].insert(*src.uintValue); // 白子的VIS while (head != tail) { const State &now = queue[head++]; UPDATE(r1, c1); UPDATE(r2, c2); } }