您的位置:首页 > 其它

[NOI2011]兔兔与蛋蛋游戏

2018-01-04 20:32 393 查看

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



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

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

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

证明:
[/b]

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

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

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

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

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
struct Node
{
int next,to;
}edge[50001];
int head[2001],num,n,m,x,y,a[101][101],id[101][101],cnt,cx[2001],ban[2001],k,ans[1001],tot;
bool vis[2001],b1,b2;
void add(int u,int v)
{
num++;
edge[num].next=head[u];
head[u]=num;
edge[num].to=v;
num++;
edge[num].next=head[v];
head[v]=num;
edge[num].to=u;
}
void build()
{int i,j;
for (i=1;i<=n;i++)
{
for (j=1;j<=m;j++)
if (((i+j)&1)^((x+y)&1)^(a[i][j]==1))
id[i][j]=++cnt;
}
for (i=1;i<=n;i++)
{
for (j=1;j<=m;j++)
if (id[i][j])
{
if (i>1&&id[i-1][j])
add(id[i][j],id[i-1][j]);
if (i<n&&id[i+1][j])
add(id[i][j],id[i+1][j]);
if (j>1&&id[i][j-1])
add(id[i][j],id[i][j-1]);
if (j<m&&id[i][j+1])
add(id[i][j],id[i][j+1]);
}
}
}
bool dfs(int x)
{int i;
for (i=head[x];i;i=edge[i].next)
{
int v=edge[i].to;
if (vis[v]==0&&ban[v]==0)
{
vis[v]=1;
if (!cx[v]||dfs(cx[v]))
{
cx[x]=v;cx[v]=x;
return 1;
}
}
}
return 0;
}
int main()
{int i,j,u,v;
char s[101];
cin>>n>>m;
for (i=1;i<=n;i++)
{
scanf("%s",s+1);
for (j=1;j<=m;j++)
{
if (s[j]=='O') a[i][j]=0;
else if (s[j]=='X') a[i][j]=1;
else if (s[j]=='.') x=i,y=j,a[i][j]=1;
}
}
build();
for (i=1;i<=n;i++)
{
for (j=1;j<=m;j++)
if (id[i][j])
{
if (!cx[id[i][j]])
{
memset(vis,0,sizeof(vis));
dfs(id[i][j]);
}
}
}
cin>>k;
for (i=1;i<=k;i++)
{
u=id[x][y];
ban[u]=1;
if (cx[u])
{
v=cx[u];
cx[u]=cx[v]=0;
memset(vis,0,sizeof(vis));
b1=(!dfs(v));
}
else b1=0;
scanf("%d%d",&x,&y);
u=id[x][y];
ban[u]=1;
if (cx[u])
{
v=cx[u];
cx[u]=cx[v]=0;
memset(vis,0,sizeof(vis));
b2=(!dfs(v));
}
else b2=0;
if (b1&&b2)
ans[++tot]=i;
scanf("%d%d",&x,&y);
}
cout<<tot<<endl;
for (i=1;i<=tot;i++)
printf("%d\n",ans[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: