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

描述

这些天,兔兔和蛋蛋喜欢上了一种新的棋类游戏。
这个游戏是在一个 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<=20
3: n=3, m=4
4~5: n=4, m=4
6~7: n=4, m=5
8: n=3, m=7
9~14: n=2, 1<=m<=40
15~16: 1<=n<=16, 1<=m<=16
17~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;
}
时间: 2024-12-23 14:01:47

bzoj 2437 [Noi2011]兔兔与蛋蛋 [二分图匹配]的相关文章

Bzoj 1562: [NOI2009]变换序列 匈牙利算法,二分图匹配

题目: http://cojs.tk/cogs/problem/problem.php?pid=409 409. [NOI2009]变换序列 ★★☆   输入文件:transform.in   输出文件:transform.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] 对于N个整数0, 1, ……, N-1,一个变换序列T可以将i变成Ti,其中 定义x和y之间的距离.给定每个i和Ti之间的距离D(i,Ti), 你需要求出一个满足要求的变换序列T.如果有多个满足条

bzoj 2437: [Noi2011]兔兔与蛋蛋

Description Solution 考虑犯错误的条件:之前是处于必胜状态,该操作之后就变成了必败状态. 我们可以把这个过程看成两人对网格图进行黑白染色,变成了一个二分图模型,即当前位置向相邻不同颜色的位置连边,构成的二分图,一次游戏相当于一个最大匹配. 一个结论:如果一定存在包含当前位置的最大匹配,那么处于先手必胜状态 证明: 因为当前点不处于最大匹配中,那么只有非匹配边可以走,假设走到了\(v\),\(v\)点则可以走匹配边,假设走了一条匹配边,则到达的下一个点只能走非匹配边,因为匹配的

【博弈+二分图匹配】[NOI2011]兔兔与蛋蛋游戏

题目描述 Description Input 输入的第一行包含两个正整数 n.m. 接下来 n行描述初始棋盘.其中第i 行包含 m个字符,每个字符都是大写英文字母"X".大写英文字母"O"或点号"."之一,分别表示对应的棋盘格中有黑色棋子.有白色棋子和没有棋子.其中点号"."恰好出现一次. 接下来一行包含一个整数 k(1≤k≤1000) ,表示兔兔和蛋蛋各进行了k次操作. 接下来 2k行描述一局游戏的过程.其中第 2i – 1

NOI2011 兔兔与蛋蛋游戏

http://www.lydsy.com/JudgeOnline/problem.php?id=2437 这道题真是极好的. 75分做法: 搜索. 出题人真的挺良心的,前15个数据点的范围都很小,可以直接搜索. #include<cstdio> #include<cstdlib> #include<iostream> #include<fstream> #include<algorithm> #include<cstring> #in

博弈论(二分图匹配):NOI 2011 兔兔与蛋蛋游戏

Description Input 输入的第一行包含两个正整数 n.m. 接下来 n行描述初始棋盘.其中第i 行包含 m个字符,每个字符都是大写英文字母"X".大写英文字母"O"或点号"."之一,分别表示对应的棋盘格中有黑色棋子.有白色棋子和没有棋子.其中点号"."恰好出现一次. 接下来一行包含一个整数 k(1≤k≤1000) ,表示兔兔和蛋蛋各进行了k次操作. 接下来 2k行描述一局游戏的过程.其中第 2i – 1行是兔兔的

[匈牙利算法][博弈] Luogu P1971 兔兔与蛋蛋

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

BZOJ 1059 矩阵游戏(神奇的二分图匹配)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1059 题意:给出一个N*N的01矩阵.有两种操作:(1)交换任意两行:(2)交换任意两列.问最后能否使得主对角线上全部为1? 思路:我们发现,对于同一行的两个1,比如 (i,j)和(i,j+1),无论如何我们也不能把这两个1都移动到主对角线上,换句话说,最多能够将其中一个1移动到主对角线上.因为,若我们想将这两 个同时移动到主对角线上,不妨设为(i1,i1),(i2,i2).首先,我们

bzoj 1059: [ZJOI2007]矩阵游戏 二分图匹配

1059: [ZJOI2007]矩阵游戏 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1891  Solved: 919[Submit][Status] Description 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏——矩阵游戏.矩阵游戏在一个N*N黑白方阵进行(如同国际象棋一般,只是颜色是随意的).每次可以对该矩阵进行两种操作:行交换操作:选择矩阵的任意两行,交换这两行(即交换对应格子的颜色)列交换操作:选择矩阵

CQUOJ D. 会做题的兔兔

D. 会做题的兔兔 Time Limit: 2000ms Memory Limit: 65536KB 64-bit integer IO format: %lld      Java class name: Main Submit Status 大家都听说梅小姐喂养了很多兔兔.梅小姐的兔兔超级萌.超级听话,经常能帮助梅小姐AC题目. 有一天,梅小姐给兔兔们一个数字,然后命令兔兔们去寻找有多少个不同的集合满足集合内的元素相加等于这个数字,并且兔兔们找的每个数都只能是2的k次幂. 比如: 梅小姐给了