[JSOI2009]游戏 题解

[JSOI2009]游戏 题解

题目地址:洛谷:【P4055】[JSOI2009]游戏 – 洛谷、BZOJ:Problem 1443. — [JSOI2009]游戏Game

题目描述

小AA和小YY得到了《喜羊羊和灰太狼》的电影票,都很想去观看,但是电影票只有一张,于是他们用智力游戏决定胜负,赢得游戏的人可以获得电影票。
在N*M的迷宫中有一个棋子,小AA首先任意选择棋子放置的位置。然后,小YY和小AA轮流将棋子移动到相邻的格子里。游戏的规则规定,在一次游戏中,同一个格子不能进入两次,且不能将棋子移动到某些格子中去。当玩家无法继续移动棋子时,游戏结束,最后一个移动棋子的玩家赢得了游戏。
例如下图所示的迷宫,迷宫中”.”表示棋子可以经过的格子,而”#”表示棋子不可以经过的格子:
.##

#.#
若小AA将棋子放置在(1,1),则小 AA 则无论如何都无法赢得游戏。
而若小AA将棋子放置在(3,2)或(2,3),则小AA能够赢得游戏。例如,小AA将棋子放置在(3,2),小YY只能将它移动到(2,2),此时小AA再将棋子移动到(2,3),就赢得了游戏。
小AA和小YY都是绝顶聪明的小朋友,且从不失误。小AA到底能不能赢得这场游戏,从而得到珍贵的电影票呢?

题意简述

有一个$n \times m$矩形地图,有的格子不能走,每次选择一个起点,然后两个玩家轮流将放在起点的棋子移动一步,只能经过同一个格子一次,最后不能移动的玩家输,求是否后手必胜。

输入输出格式

输入格式:
输入数据首先输入两个整数 N,M,表示了迷宫的边长。接下来 N 行,每行 M 个字符,描述了迷宫。

输出格式:
若小 AA 能够赢得游戏,则输出一行”WIN”,然后输出所有可以赢得游戏的起始位置,按行优先顺序输出,每行一个。否则输出一行”LOSE”(不包含引号)。

输入输出样例

输入样例#1:

3 3
.##
...
#.#

输出样例#1:

WIN
2 3
3 2

说明

对30%的数据,有1<=n,m<=5
对100%的数据,有1<=n,m<=100

题解

首先对矩形黑白染色,连边成为二分图,我们发现,可以利用匈牙利算法中的交错路来解决这个问题。首先跑一遍最大匹配。
如果为完美匹配的状况,当选择任何一个匹配点为出发点,则先手一定每次走一条匹配边,而最后一条边也是匹配边,先手必胜。
否则,先手从非匹配点出发,无论如何都会走到一个匹配点上,此时,后手会经历类似上面的情况,后手必胜。由于还要输出方案,我们还要找最大匹配时一定不是匹配点的点,可以从非匹配点出发寻找交错路,与非匹配点在二分图中同边的点都是答案。

代码

// Code by KSkun, 2018/7
#include <cstdio>
#include <cctype>
#include <cstring>

#include <algorithm>
#include <vector>

typedef long long LL;

inline char fgc() {
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2)
        ? EOF : *p1++;
}

inline LL readint() {
    register LL res = 0, neg = 1; register char c = fgc();
    for(; !isdigit(c); c = fgc()) if(c == '-') neg = -1;
    for(; isdigit(c); c = fgc()) res = (res << 1) + (res << 3) + c - '0';
    return res * neg;
}

inline char readsingle() {
    char c;
    while(!isgraph(c = fgc())) {}
    return c;
}

const int MAXN = 10005;
const int fix[][4] = {{1, 0, -1, 0}, {0, 1, 0, -1}};

int n, m;

std::vector<int> gra[MAXN];

int match[MAXN], vis[MAXN], clk;

bool dfs(int u) {
    for(int i = 0; i < gra[u].size(); i++) {
        int v = gra[u][i];
        if(vis[v] != clk) {
            vis[v] = clk;
            if(!match[v] || dfs(match[v])) {
                match[v] = u; match[u] = v; return true;
            }
        }
    }
    return false;
}

inline int bmatch() {
    int res = 0;
    for(int i = 1; i <= n * m; i++) {
        if(!match[i]) {
            clk++; if(dfs(i)) res++;
        }
    }
    return res;
}

bool ans[MAXN];

void dfs_ans(int u) {
    if(ans[u]) return;
    ans[u] = true;
    for(int i = 0; i < gra[u].size(); i++) {
        int v = gra[u][i];
        if(match[v]) dfs_ans(match[v]);
    }
}

inline int id(int x, int y) {
    return (x - 1) * m + y;
}

inline int col(int x, int y) {
    return (x + y) & 1;
}

char mmp[105][105];

int main() {
    n = readint(); m = readint();
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            mmp[i][j] = readsingle();
        }
    }
    int tot = 0;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            if(mmp[i][j] == '#') continue;
            tot++;
            if(col(i, j)) continue;
            for(int k = 0; k < 4; k++) {
                int nx = i + fix[0][k], ny = j + fix[1][k];
                if(nx < 1 || nx > n || ny < 1 || ny > m || mmp[nx][ny] == '#') continue;
                gra[id(i, j)].push_back(id(nx, ny));
                gra[id(nx, ny)].push_back(id(i, j));
            }
        }
    }
    if(bmatch() * 2 == tot) {
        puts("LOSE"); return 0;
    }
    puts("WIN");
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            if(!match[id(i, j)]) {
                dfs_ans(id(i, j));
            }
        }
    }
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            if(mmp[i][j] != '#' && ans[id(i, j)]) {
                printf("%d %d\n", i, j);
            }
        }
    }
    return 0;
}


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据