1. 程式人生 > >【洛谷P3930】SAC E#1 - 一道大水題 Knight

【洛谷P3930】SAC E#1 - 一道大水題 Knight

輸入 告訴 com space count es2017 所在 false ....

題目背景

毒奶色和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