[Noi2011]兔兔与蛋蛋

题目

 

 

题解

容易想到空格移动的路径是不会自交的。

因为空格移动的路径是黑白棋相间的

所以对棋盘进行黑白染色,建立二分图

如果黑白两格上的棋子不一样则可以连边

如果一个人(A)将空格移入了一个在最大匹配内的点,那么它的对手(B)就可以沿着匹配边前进(否则就相当于找到了一条新的匹配边)

而A只能沿着非匹配边前进,这样到最后肯定是A无路可走(否则就相当于找到了一条新的匹配边)

所以如果起始点不在最大匹配中那么先手只能走非匹配边,即必败。

另外有可能起始点在最大匹配中,但后手可以沿着另一个最大匹配前进。

所以必须保证起始点必须在最大匹配中。

具体的话可以给这个点打个删除标记,看看它的原匹配点能不能找到另一个对象。

形成代码就是先跑一边匈牙利

然后对于每个操作(把兔兔与蛋蛋的拆开),把经过的点全部删除,看看空格是否必须在最大匹配中。

注意

每执行完一次操作要清vis

黑白染色时相邻行要错开

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
#define N 2000
#define pos(i,j) ((i-1)*m+j)
char map[50][50];
vector<int> vec[N];
int mx[4]={0,0,1,-1},my[4]={1,-1,0,0},p[N],vis[N],match[N],win[N],n,m;
bool disable[N];
void build(int i,int j)
{
	for(int k=0;k<4;k++)
	{
		int tx=i+mx[k],ty=j+my[k];
		if(abs(map[i][j]-map[tx][ty])==1) vec[pos(i,j)].push_back(pos(tx,ty));
	}
}
bool dfs(int id)
{
	for(int i=0;i<vec[id].size();i++)
	{
		int to=vec[id][i];
		if(vis[to]||disable[to]) continue;
		vis[to]=true;
		if(!match[to]||dfs(match[to]))
		{
			match[id]=to;
			match[to]=id;
			return true;
		}
	}
	return false;
}
int hungary()
{
	int ret=0;
	memset(match,0,sizeof(match));
	for(int i=1;i<=n;i++) for(int j=1+((i-1)&1);j<=m;j+=2)
	{
		memset(vis,0,sizeof(vis));
		ret+=dfs(pos(i,j));
	}
	return ret;
}
int ans[N];
int main()
{
	int sx,sy,step;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			scanf(" %c",&map[i][j]);
			if(map[i][j]=='.') sx=i,sy=j,map[i][j]=3;
			else if(map[i][j]=='X') map[i][j]=3;
			else map[i][j]=2;
		}
	}
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) build(i,j);//建边
	hungary();
	cin>>step;
	for(int i=1;i<=step*2;i++)
	{
		memset(vis,0,sizeof(vis));
		disable[pos(sx,sy)]=true;
		//win[i]:在当前状态下是否有必胜策略
		win[i]=(match[pos(sx,sy)])&&(!dfs(match[pos(sx,sy)]));//如果空格不必须在最大匹配中
		if(win[i]) match[match[pos(sx,sy)]]=0;//释放匹配的点
		scanf("%d%d",&sx,&sy);
	}
	int cnt=0;
	for(int i=1;i<step*2;i+=2)
	{
		if(win[i]&&win[i+1]) ans[++cnt]=(i+1)/2;
	}
	cout<<cnt<<endl;
	for(int i=1;i<=cnt;i++) printf("%d\n", ans[i]);
}

  

posted @ 2020-06-10 14:06  linzhuohang  阅读(180)  评论(0编辑  收藏  举报