[bzoj2437]兔兔与蛋蛋

移动可以理解为空白格的移动,问题等价于双方在一张无向图(相邻不同色点连边,起点视为黑色)移动,不能经过重复的点,无法移动者为负
由于这张图是二分图,因此有结论,先手必胜当且仅当起点一定在任意一组最大匹配中
证明:
必要性,即先手必胜=>一定在匹配中,其等价于不在匹配中=>后手必胜,考虑一组最大匹配,容易发现先手所走到的点一定在最大匹配中(否则匹配可以增大),而后手的策略就是一直走到那个点的匹配上,一定必胜
充分性,即一定在匹配中=>先手必胜,那么当去掉起点后的最大匹配中,一定存在某一个点使得其可以不在剩下点的最大匹配中,即这个点后手必胜,那么先手走到这个点即可
具体实现就是说先将其他节点的最大匹配求出,然后再加入这个节点判断能否增大,每一步都只需要重新判断新的空格即可
(其实这个东西就是说让答案+1即存在一条增广路,而增广路一定是奇数条边,所以差不多就是这样了)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 2005
 4 struct ji{
 5     int nex,to;
 6 }edge[N<<3];
 7 int E,n,m,k,x,y,dx[4]={-1,0,0,1},dy[4]={0,-1,1,0},a[N],vis[N],ans[N],mat[N],head[N];
 8 char s[105][105];
 9 int id(int x,int y){
10     return x*m+y+1;
11 }
12 void add(int x,int y){
13     edge[E].nex=head[x];
14     edge[E].to=y;
15     head[x]=E++;
16     if (E&1)add(y,x);
17 }
18 int dfs(int k){
19     if ((k<0)||(vis[k]))return 0;
20     vis[k]=1;
21     for(int i=head[k];i!=-1;i=edge[i].nex){
22         int v=edge[i].to;
23         if ((!mat[v])||(dfs(mat[v]))){
24             mat[v]=k;
25             mat[k]=v;
26             return 1;
27         }
28     }
29     return 0;
30 }
31 int main(){
32     scanf("%d%d",&n,&m);
33     for(int i=0;i<n;i++)scanf("%s",s[i]);
34     memset(head,-1,sizeof(head));
35     for(int i=0;i<n;i++)
36         for(int j=0;j<m;j++)
37             if (s[i][j]!=‘O‘)
38                 for(int k=0;k<4;k++){
39                     x=i+dx[k];
40                     y=j+dy[k];
41                     if ((x>=0)&&(y>=0)&&(x<n)&&(y<m)&&(s[x][y]==‘O‘))add(id(i,j),id(x,y));
42                 }
43     for(int i=0;i<n;i++)
44         for(int j=0;j<m;j++){
45             if (s[i][j]==‘.‘){
46                 x=i+1;
47                 y=j+1;
48             }
49             if (s[i][j]!=‘O‘){
50                 memset(vis,0,sizeof(vis));
51                 dfs(id(i,j));
52             }
53         }
54     scanf("%d",&k);
55     for(int i=0;i<(k<<1);i++){
56         if (i)scanf("%d%d",&x,&y);
57         int z=mat[id(--x,--y)];
58         mat[id(x,y)]=-1;
59         if (z>0){
60             mat[z]=0;
61             memset(vis,0,sizeof(vis));
62             a[i]=(!dfs(z));
63         }
64         if ((i&1)&&(a[i-1])&&(a[i]))ans[++ans[0]]=i/2+1;
65     }
66     for(int i=0;i<=ans[0];i++)printf("%d\n",ans[i]);
67 }

原文地址:https://www.cnblogs.com/PYWBKTDA/p/11818028.html

时间: 2024-10-18 21:26:19

[bzoj2437]兔兔与蛋蛋的相关文章

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

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

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

描述 这些天,兔兔和蛋蛋喜欢上了一种新的棋类游戏. 这个游戏是在一个 n 行 m 列的棋盘上进行的.游戏开始之前,棋盘上有一 个格子是空的,其它的格子中都放置了一枚棋子,棋子或者是黑色,或者是白色. 每一局游戏总是兔兔先操作,之后双方轮流操作,具体操作为: 兔兔每次操作时,选择一枚与空格相邻的白色棋子,将它移进空格. 蛋蛋每次操作时,选择一枚与空格相邻的黑色棋子,将它移进空格. 第一个不能按照规则操作的人输掉游戏. 最近兔兔总是输掉游戏,而且蛋蛋格外嚣张,于是兔兔想请她的好朋友-- 你--来帮助

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

题目描述 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). 例如下面

CQUOJ D. 会做题的兔兔

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

bzoj2437 [Noi2011]兔兔与蛋蛋

二分图博弈果然都是一个套路,必经点必胜,非必经点必败, 但是肯定不能没走一步就重新建图判断必胜还是必败,那么我们可以这样:每走一步就把这个点删掉,然后find他原来的匹配,如果找不到,就说明他是必经点,否则就是非必经点. 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #define

bzoj 2437: [Noi2011]兔兔与蛋蛋

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

生兔兔

从前有一对长寿兔子,它们每一个月生一对兔子,新生的小兔子两个月就长大了,在第二个月的月底开始生它们的下一代小兔子,这样一代一代生下去,求解兔子增长数量的数列.Input第1行是测试数据的组数n,后面跟着n行输入.每组测试数据占1行,包括一个正整数a(1 <= a <= 20)Output输出有1行,每行输出对应一个输入.输出应是一个正整数序列,整数之间用空格分开.Sample Input 3 3 2 1 Sample Output 1 1 2 1 1 1 import java.util.Sc