[NOI2011]兔兔与蛋蛋游戏

Description

Input

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

Output

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

Sample Input

样例一:
1 6
XO.OXO
1
1 2
1 1
样例二:
3 3
XOX
O.O
XOX
4
2 3
1 3
1 2
1 1
2 1
3 1
3 2
3 3
样例三:
4 4
OOXX
OXXO
OO.O
XXXO
2
3 2
2 2
1 2
1 3

Sample Output

样例一:
1
1
样例二:
0
样例三:
2
1
2

样例1对应图一中的游戏过程
样例2对应图三中的游戏过程

HINT

想看详细的图和分析,可以参考https://www.cnblogs.com/maijing/p/4703094.html

我们可以把这个过程看成两人对网格图进行黑白染色,变成了一个二分图模型,即当前位置向相邻不同颜色的位置连边,构成的二分图,一次游戏相当于一个最大匹配.

最重要的一个结论:如果一定存在包含当前位置的最大匹配,那么处于先手必胜状态
证明:

因为当前点不处于最大匹配中,那么只有非匹配边可以走,假设走到了\(v\),\(v\)点则可以走匹配边,假设走了一条匹配边,则到达的下一个点只能走非匹配边,因为匹配的点是\(v\), 综上:先手只能一直沿着非匹配边走,而后手有匹配边可以走,所以不是必胜状态

所以只需要判断一个点是否在一定在最大匹配中了
方法是:删除该点,再跑一次最大匹配,如果能成功匹配则不满足条件.

 

一个细节:一定不会存在回路,即一个点只会走一次,所以走过的点不能再进入匹配中

转载自http://www.cnblogs.com/Yuzao/p/8146313.html

 

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 using namespace std;
  7 struct Node
  8 {
  9   int next,to;
 10 }edge[50001];
 11 int head[2001],num,n,m,x,y,a[101][101],id[101][101],cnt,cx[2001],ban[2001],k,ans[1001],tot;
 12 bool vis[2001],b1,b2;
 13 void add(int u,int v)
 14 {
 15   num++;
 16   edge[num].next=head[u];
 17   head[u]=num;
 18   edge[num].to=v;
 19   num++;
 20   edge[num].next=head[v];
 21   head[v]=num;
 22   edge[num].to=u;
 23 }
 24 void build()
 25 {int i,j;
 26   for (i=1;i<=n;i++)
 27     {
 28       for (j=1;j<=m;j++)
 29     if (((i+j)&1)^((x+y)&1)^(a[i][j]==1))
 30       id[i][j]=++cnt;
 31     }
 32   for (i=1;i<=n;i++)
 33     {
 34       for (j=1;j<=m;j++)
 35     if (id[i][j])
 36       {
 37         if (i>1&&id[i-1][j])
 38           add(id[i][j],id[i-1][j]);
 39         if (i<n&&id[i+1][j])
 40           add(id[i][j],id[i+1][j]);
 41         if (j>1&&id[i][j-1])
 42           add(id[i][j],id[i][j-1]);
 43         if (j<m&&id[i][j+1])
 44           add(id[i][j],id[i][j+1]);
 45       }
 46     }
 47 }
 48 bool dfs(int x)
 49 {int i;
 50   for (i=head[x];i;i=edge[i].next)
 51     {
 52       int v=edge[i].to;
 53       if (vis[v]==0&&ban[v]==0)
 54     {
 55       vis[v]=1;
 56       if (!cx[v]||dfs(cx[v]))
 57         {
 58           cx[x]=v;cx[v]=x;
 59           return 1;
 60         }
 61     }
 62     }
 63   return 0;
 64 }
 65 int main()
 66 {int i,j,u,v;
 67   char s[101];
 68   cin>>n>>m;
 69   for (i=1;i<=n;i++)
 70     {
 71       scanf("%s",s+1);
 72       for (j=1;j<=m;j++)
 73     {
 74       if (s[j]=='O') a[i][j]=0;
 75       else if (s[j]=='X') a[i][j]=1;
 76       else if (s[j]=='.') x=i,y=j,a[i][j]=1;
 77     }
 78     }
 79   build();
 80   for (i=1;i<=n;i++)
 81     {
 82       for (j=1;j<=m;j++)
 83     if (id[i][j])
 84       {
 85         if (!cx[id[i][j]])
 86           {
 87         memset(vis,0,sizeof(vis));
 88         dfs(id[i][j]);
 89           }
 90       }
 91     }
 92   cin>>k;
 93   for (i=1;i<=k;i++)
 94     {
 95       u=id[x][y];
 96       ban[u]=1;
 97       if (cx[u])
 98     {
 99       v=cx[u];
100       cx[u]=cx[v]=0;
101       memset(vis,0,sizeof(vis));
102       b1=(!dfs(v));
103     }
104       else b1=0;
105       scanf("%d%d",&x,&y);
106       u=id[x][y];
107       ban[u]=1;
108       if (cx[u])
109     {
110       v=cx[u];
111       cx[u]=cx[v]=0;
112       memset(vis,0,sizeof(vis));
113       b2=(!dfs(v));
114     }
115       else b2=0;
116       if (b1&&b2)
117     ans[++tot]=i;
118       scanf("%d%d",&x,&y);
119     }
120   cout<<tot<<endl;
121   for (i=1;i<=tot;i++)
122     printf("%d\n",ans[i]);
123 }

 

posted @ 2018-01-04 20:32  Z-Y-Y-S  阅读(617)  评论(0编辑  收藏  举报