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