P4055 [JSOI2009] 游戏(博弈论,最大匹配)

P4055 [JSOI2009] 游戏

文章目录

  • P4055 [JSOI2009] 游戏
    • 题目传送门
    • 题目大意 :
    • 思路:
    • code

题目传送门

题目大意 :

小AA和小YY玩游戏,在这个游戏中,同一个格子不能进入两次,且不能将棋子移动到某些格子中去。当玩家无法继续移动棋子时,游戏结束,最后一个移动棋子的玩家赢得了游戏。由小AA决定棋子的初始位置 , 求小AA能够赢得游戏的棋子的初始位置。

思路:

将棋盘黑白染色,能够到达的两个点之间连一条双向边,求原图的最大匹配。
每种最大匹配方案中的未匹配点都是能够赢得游戏的点。
先手只要先走未匹配点,不管如何后手走完之后,先手都可以找到一个位置走。
如果原图能够完美匹配,那么先手无论走哪里,后手都可以走它的匹配点,所以先手必输。
不用分x部和y部
听说数据没有Lose?

code

#include 
#define fu(x, y, z) for (int x = y; x <= z; x++)
using namespace std;
const int N = 105;
struct E {
    int to, nt;
} e[N * N * 4];
struct A {
    int x, y;
} ans[N * N];
int sum, n, m, mp[N][N], num1, pj[N][N], f[N * N], hd[N * N], cnt, ans1, vis[N * N], dx[4] = { 0, 0, 1, -1 } , dy[4] = { -1, 1, 0, 0 };
char ch;
void add(int x, int y) { e[++cnt].to = y, e[cnt].nt = hd[x], hd[x] = cnt; }
int xyl(int x) {
    int y;
    for (int i = hd[x]; i; i = e[i].nt) {
        y = e[i].to;
        if (vis[y])
            continue;
        vis[y] = 1;
        if (!f[y] || xyl(f[y])) {
            f[f[x]] = 0;
            f[y] = x;
            f[x] = y;
            return true;
        }
    }
    return false;
}
int read () {
    int val = 0 , fu = 1;
    char ch = getchar ();
    while (ch < '0' || ch >'9') {
        if (ch == '-') fu = -1;
        ch = getchar ();
    }
    while (ch >= '0' && ch <= '9') {
        val = val * 10 + (ch - '0');
        ch = getchar ();
    }
    return val * fu;
}
int main() {
    scanf("%d%d", &n, &m);
    fu(i, 1, n) {
        fu(j, 1, m) {
            ch = getchar();
            while (ch != '.' && ch != '#') ch = getchar();
            mp[i][j] = (ch == '#');
        }
    }
    fu(i, 1, n)
        fu(j, 1, m)
            pj[i][j] = ++num1;
    int x, y;
    fu(i, 1, n) {
        fu(j, 1, m) {
            if (mp[i][j])
                continue;
            fu(k, 0, 3) {
                x = dx[k] + i, y = dy[k] + j;
                if (x < 1 || x > n || y < 1 || y > m || mp[x][y])
                    continue;
                add(pj[i][j], pj[x][y]);
            }
        }
    }
    fu(i, 1, n) {
        fu(j, 1, m) {
            if (f[pj[i][j]] || mp[i][j])
                continue;
            memset(vis, 0, sizeof(vis));
            sum += xyl(pj[i][j]);
        }
    }
    fu(i, 1, n) {
        fu(j, 1, m) {
            if (mp[i][j])
                continue;
            memset(vis, 0, sizeof(vis));
            if (!f[pj[i][j]] || xyl(f[pj[i][j]])) {
                ans[++ans1].x = i, ans[ans1].y = j;
            }
        }
    }
    puts(ans1 ? "WIN" : "LOSE");
    fu(i, 1, ans1) printf("%d %d\n", ans[i].x, ans[i].y);
    return 0;
}

你可能感兴趣的:(博弈论,二分图匹配,最大匹配,c++)