【洛谷P3930】SAC E#1 - 一道大水題 Knight
題目背景
毒奶色和F91是好朋友。
題目描述
他們經常在一起玩一個遊戲,不,不是星際爭霸,是國際象棋。
毒奶色覺得F91是一只雞。他在一個n×n的棋盤上用黑色的城堡(車)、騎士(馬)、主教(象)、皇後(副)、國王(帥)、士兵(卒)擺了一個陣。
然而F91覺得毒奶色是一只雞。他發起了挑戰:他要操縱一個白色騎士,不經過任何一個棋子的攻擊範圍(F91可以連續行動,而毒奶色的棋子不會動,除非白騎士進入了對方的攻擊範圍),並擊殺毒奶色的國王(即進入黑國王所在的位置)。
請告訴F91他最少需要多少步驟來完成這一項壯舉。
註意:
1.當F91的白騎士走到毒奶色的棋子所在的格子上的時候,會擊殺(吃掉)該棋子。這個棋子也就不再對F91的白騎士有威脅了。
2.如果白騎士開場就在黑子的攻擊範圍內,則立刻被擊殺、F91立刻失敗。
3.即使白騎士在攻擊王的瞬間進入了其他棋子攻擊範圍(即其他棋子“看護”著王所在的格子),依然算F91獲勝。
攻擊範圍:
城堡:橫、豎方向所有位置,直到被一個其他棋子阻攔。
..#..
..#..
##C##
..#..
..#..
騎士:橫2豎1或者橫1豎2的所有位置(最多8個,類似日字)。
.#.#.
#...#
..K..
#...#
.#.#.
主教:斜向(45°)所有位置,直到被一個其他棋子阻攔。
#...#
.#.#.
..B..
.#.#.
#...#
皇後:城堡和主教的結合體(既能橫/豎向攻擊,也能45°角斜向攻擊,直到被其他棋子阻擋)。
#.#.#
.###.
##Q##
.###.
#.#.#
國王:身邊8連通位置的8個格子。
.....
.###.
.#X#.
.###.
.....
士兵:左下方/右下方(45°)的格子(最多2個)。
.....
.....
..P..
.#.#.
.....
其中字母表示棋子類型,參考輸入格式。
‘#’表示可攻擊範圍。
輸入輸出格式
輸入格式:
輸入包含多組數據。
每一組數據中,第一行一個整數n表示棋盤規模。
接下來n行,每行一個長度為n的字符串。描述棋盤的格局。
其中:
.表示空
O表示白騎士
C表示黑城堡
K表示黑騎士
B表示黑主教
Q表示黒皇後
X表示黑國王
P表示黑士兵
輸出格式:
對於每一個測試數據,每行輸出一個整數,表示F91的最小步數。
如果無論F91如何行動也無法擊殺黑國王,輸出-1。
輸入輸出樣例
輸入樣例#1:8 ...X.... ........ ........ ........ ........ ........ ........ ......O.輸出樣例#1:
4輸入樣例#2:
8 ......X. ........ .O...... ...P.Q.C .....B.. ........ ...K.... ........輸出樣例#2:
7
說明
輸入最多包含5組數據。
對於20%的數據,毒奶色只有國王。n <= 8。
對於30%的數據,毒奶色只有國王、騎士。n <= 8。
對於60%的數據,毒奶色只有國王、騎士、王後。n <= 50。
對於100%的數據,毒奶色可以有全套16顆棋子(2城堡,2騎士,2主教,1後,1王,8兵)。n <= 50。
溫馨提示:
時間限制可能比想象之中還要更緊一點,請註意實現細節以保證性能。
樣例2解釋:
一種可行的做法是:
......X.
.3..6...
.O5.....
4.2P.Q.C
1....B..
........
...K....
........
分析
狀態壓縮的寬搜。
代碼
#include <iostream> #include <cstdio> #include <cstring> #include <unordered_set> #include <queue> using namespace std; const size_t MaxN = 80; const int Dx[] = {1, 1, 2, 2, -1, -1, -2, -2}, Dy[] = {2, -2, 1, -1, 2, -2, 1, -1}; struct QueTp { int i, j, step, state; } ; queue<QueTp> Q; int N, Si, Sj; char A[MaxN][MaxN]; int ID[MaxN][MaxN], Tot; unordered_set<int> Vis[MaxN][MaxN]; bool Check(const int& state, const int& i, const int& j) { if(Vis[i][j].count(state)) return false; for(int x = i + 1; x <= N; ++x) if(A[x][j] != ‘.‘ && !((1 << ID[x][j]) & state)) { if(A[x][j] == ‘C‘ || A[x][j] == ‘Q‘) return false; break; } for(int x = i - 1; x > 0; --x) if(A[x][j] != ‘.‘ && !((1 << ID[x][j]) & state)) { if(A[x][j] == ‘C‘ || A[x][j] == ‘Q‘) return false; break; } for(int x = j + 1; x <= N; ++x) if(A[i][x] != ‘.‘ && !((1 << ID[i][x]) & state)) { if(A[i][x] == ‘C‘ || A[i][x] == ‘Q‘) return false; break; } for(int x = j - 1; x > 0; --x) if(A[i][x] != ‘.‘ && !((1 << ID[i][x]) & state)) { if(A[i][x] == ‘C‘ || A[i][x] == ‘Q‘) return false; break; } for(int x = i - 1, y = j - 1; x > 0 && y > 0; --x, --y) if(A[x][y] != ‘.‘ && !((1 << ID[x][y]) & state)) { if(A[x][y] == ‘B‘ || A[x][y] == ‘Q‘) return false; break; } for(int x = i - 1, y = j + 1; x > 0 && y <= N; --x, ++y) if(A[x][y] != ‘.‘ && !((1 << ID[x][y]) & state)) { if(A[x][y] == ‘B‘ || A[x][y] == ‘Q‘) return false; break; } for(int x = i + 1, y = j - 1; x <= N && y > 0; ++x, --y) if(A[x][y] != ‘.‘ && !((1 << ID[x][y]) & state)) { if(A[x][y] == ‘B‘ || A[x][y] == ‘Q‘) return false; break; } for(int x = i + 1, y = j + 1; x <= N && y <= N; ++x, ++y) if(A[x][y] != ‘.‘ && !((1 << ID[x][y]) & state)) { if(A[x][y] == ‘B‘ || A[x][y] == ‘Q‘) return false; break; } for(int t = 0; t != 8; ++t) { int x = i + Dx[t], y = j + Dy[t]; if(x > 0 && y > 0 && x <= N && y <= N && A[x][y] == ‘K‘) return false; } if(i != 1 && ((j != N && A[i - 1][j + 1] == ‘P‘ && !((1 << ID[i - 1][j + 1]) & state)) || (j != 1 && A[i - 1][j - 1] == ‘P‘ && !((1 << ID[i - 1][j - 1]) & state)))) return false; for(int x = i - 1; x <= i + 1; ++x) { if(x < 1 || x > N) continue; for(int y = j - 1; y <= j + 1; ++y) if(y > 0 && y <= N && A[x][y] == ‘X‘) return false; } return true; } void Work() { Q = queue<QueTp>(), Tot = 0; memset(ID, -1, sizeof(ID)); memset(A, 0, sizeof(A)); for(int i = 1; i <= N; i++) { scanf("%s", A[i] + 1); for(int j = 1; j <= N; j++) { if(A[i][j] == ‘O‘) Si = i, Sj = j, A[i][j] = ‘.‘; else if(A[i][j] == ‘C‘ || A[i][j] == ‘K‘ || A[i][j] == ‘B‘ || A[i][j] == ‘Q‘ || A[i][j] == ‘X‘ || A[i][j] == ‘P‘) ID[i][j] = Tot++; else A[i][j] = ‘.‘; Vis[i][j].clear(); } } if(!Check(0, Si, Sj)) { puts("-1"); return; } Vis[Si][Sj].insert(0); Q.push((QueTp) {Si, Sj, 0, 0}); while(!Q.empty()) { for(int i = 0; i != 8; ++i) { int x = Q.front().i + Dx[i], y = Q.front().j + Dy[i], state = Q.front().state; if(x < 1 || x > N || y < 1 || y > N) continue; if(A[x][y] == ‘X‘) { printf("%d\n", Q.front().step + 1); return; } if(A[x][y] != ‘.‘) state |= 1 << ID[x][y]; if(Check(state, x, y)) Vis[x][y].insert(state), Q.push((QueTp) {x, y, Q.front().step + 1, state}); } Q.pop(); } puts("-1"); } int main() { while(cin >> N) Work(); return 0; }
【洛谷P3930】SAC E#1 - 一道大水題 Knight