[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 }
View Code

 

posted @ 2019-11-08 09:01  PYWBKTDA  阅读(150)  评论(0编辑  收藏  举报