bzoj 2437 [Noi2011]兔兔与蛋蛋 [二分图匹配]

来源:互联网 发布:淘宝网一件代发可信吗 编辑:程序博客网 时间:2024/05/01 19:51

描述

这些天,兔兔和蛋蛋喜欢上了一种新的棋类游戏。这个游戏是在一个 n 行 m 列的棋盘上进行的。游戏开始之前,棋盘上有一个格子是空的,其它的格子中都放置了一枚棋子,棋子或者是黑色,或者是白色。每一局游戏总是兔兔先操作,之后双方轮流操作,具体操作为:兔兔每次操作时,选择一枚与空格相邻的白色棋子,将它移进空格。蛋蛋每次操作时,选择一枚与空格相邻的黑色棋子,将它移进空格。第一个不能按照规则操作的人输掉游戏。

这里写图片描述
这里写图片描述
这里写图片描述

最近兔兔总是输掉游戏,而且蛋蛋格外嚣张,于是兔兔想请她的好朋友——你——来帮助她。她带来了一局输给蛋蛋的游戏的实录,请你指出这一局游戏中所有她“犯错误”的地方。注意:两个格子相邻当且仅当它们有一条公共边。兔兔的操作是“犯错误”的,当且仅当,在这次操作前兔兔有必胜策略,而这次操作后蛋蛋有必胜策略。

格式

输入格式

输入的第一行包含两个正整数 n、m。接下来 n行描述初始棋盘。其中第i 行包含 m个字符,每个字符都是大写英文字母"X"、大写英文字母"O"或点号"."之一,分别表示对应的棋盘格中有黑色棋子、有白色棋子和没有棋子。其中点号"."恰好出现一次。接下来一行包含一个整数 k(1≤k≤1000) ,表示兔兔和蛋蛋各进行了k次操作。接下来 2k行描述一局游戏的过程。其中第 2i – 1行是兔兔的第 i 次操作(编号为i的操作) ,第2i行是蛋蛋的第i次操作。每个操作使用两个整数x,y来描述,表示将第x行第y列中的棋子移进空格中。输入保证整个棋盘中只有一个格子没有棋子, 游戏过程中兔兔和蛋蛋的每个操作都是合法的,且最后蛋蛋获胜。

输出格式

输出文件的第一行包含一个整数r,表示兔兔犯错误的总次数。接下来r 行按递增的顺序给出兔兔“犯错误”的操作编号。其中第 i 行包含一个整数ai表示兔兔第i 个犯错误的操作是他在游戏中的第 ai次操作。

样例1

样例输入1

1 6 XO.OXO 1 1 2 1 1 

样例输出1

1 1 

样例2

样例输入2

3 3 XOX O.O XOX 4 2 3 1 3 1 2 1 1 2 1 3 1 3 2 3 3 

样例输出2

0

样例3

样例输入3

4 4 OOXX OXXO OO.O XXXO 2 3 2 2 2 1 2 1 3 

样例输出3

2 1 2 

提示

1~2: n=1, 1<=m<=203: n=3, m=44~5: n=4, m=46~7: n=4, m=58: n=3, m=79~14: n=2, 1<=m<=4015~16: 1<=n<=16, 1<=m<=1617~20: 1<=n<=40, 1<=m<=40

Solution

可以看做是将空格按照黑白交替的方式移动。
先把格子黑白染色,不妨令起点为黑色,相邻且颜色不同的格子连边。连边时注意,假设起点坐标为(x,y),且(x+y)%2=0,则只有同样横纵坐标之和为奇数的黑格子才有用。

如果起点在一定最大匹配中,则一定先手必胜。因为起点一定在奇数边的交错轨中,只要每次都沿着匹配的边走,一定可以赢。

如果起点不一定在最大匹配中,则后手必胜。因为第一步走到的点,一定在不包括起点的最大匹配中。

所以只要当前点一定在最大匹配中就是必胜态,如果走之前是必胜态,走之后还是必胜态,那么说明这一步就走错了。

#include <bits/stdc++.h>using namespace std;int n, m;int arr[45][45];int tot;int x, y;int num[45][45];vector<int> edges[10005];bool vis[10005], ban[10005];int mat[10050];bool dfs(int i) {    if (ban[i]) return false;    for (int j = 0; j < edges[i].size(); j++) {        int k = edges[i][j];        if (!vis[k] && !ban[k]) {            vis[k] = 1;            if (!mat[k] || dfs(mat[k])) {                mat[k] = i;                mat[i] = k;                return true;            }        }    }    return false;}int ans[10005];int main() {    scanf("%d %d", &n, &m);    char str[45];    for (int i = 1; i <= n; i++) {        scanf("%s", str + 1);        for (int j = 1; j <= m; j++) {            if (str[j] == 'O') arr[i][j] = 1;            else if (str[j] == 'X') arr[i][j] = 2;            else arr[i][j] = 2, x = i, y = j;        }    }    for (int i = 1; i <= n; i++)        for (int j = 1; j <= m; j++)            if (arr[i][j] == 1 ^ (((i + j) & 1) == ((x + y) & 1)))                num[i][j] = ++tot;    for (int i = 1; i <= n; i++) {        for (int j = 1; j <= m; j++) {            if (!num[i][j]) continue;            if (num[i + 1][j]) {                edges[num[i][j]].push_back(num[i + 1][j]);                edges[num[i + 1][j]].push_back(num[i][j]);            }            if (num[i][j + 1]) {                edges[num[i][j]].push_back(num[i][j + 1]);                edges[num[i][j + 1]].push_back(num[i][j]);            }        }    }    for (int i = 1; i <= tot; i++) {        memset(vis, 0, sizeof(vis));        if (!mat[i]) dfs(i);    }    int k;    scanf("%d", &k);    for (int i = 1; i <= k << 1; i++) {        int fuck = num[x][y];        ban[fuck] = 1;        if (mat[fuck]) {            int match = mat[fuck];            mat[match] = mat[fuck] = 0;            memset(vis, 0, sizeof(vis));            ans[i] = (!dfs(match));        }        scanf("%d %d", &x, &y);    }    int res = 0;    for (int i = 1; i <= k; i++)        res += (ans[i * 2 - 1] & ans[i * 2]);    printf("%d\n", res);    for (int i = 1; i <= k; i++) {        if (ans[i * 2 - 1] & ans[i * 2]) {            printf("%d\n", i);        }    }    return 0;}
0 0
原创粉丝点击