loj雅礼集训 2017 Day2」棋盘游戏(二分图博弈之最大匹配必须点)

之前看了下二分图博弈,觉得理解了

这道板子题,我居然又困惑了好久!!真想抽自己~


明显看出这是一张二分图,我们用 i + j i+j i+j的奇偶性分类

接下来就可以套二分图博弈的板子了

(注意,下面是把先选择第一步棋子放哪里的人认为是先手,也就是Alice)

Ⅰ . 结 论 一 : \color{Red}Ⅰ.结论一: .:

若 先 手 选 择 的 点 可 能 不 在 最 大 匹 配 中 必 胜 若先手选择的点可能不在最大匹配中必胜

若 先 手 选 择 的 点 一 定 在 最 大 匹 配 中 必 败 若先手选择的点一定在最大匹配中必败

我写的理论证明,感觉还行

所 以 现 在 知 道 一 个 点 一 定 在 最 大 匹 配 中 , 先 跑 网 络 流 所以现在知道一个点一定在最大匹配中,先跑网络流 ,

若 s 到 这 个 点 满 流 且 残 量 网 络 中 不 存 在 s 到 这 个 点 的 路 径 , 一 定 是 必 须 点 若s到这个点满流且残量网络中不存在s到这个点的路径,一定是必须点 ss,

此 时 是 必 败 的 , 否 则 必 胜 \color{Red}此时是必败的,否则必胜 ,

当 然 先 手 选 的 点 可 以 在 二 分 图 左 边 , 也 可 以 在 二 分 图 右 边 当然先手选的点可以在二分图左边,也可以在二分图右边 ,

所 以 再 建 图 从 t 向 s 跑 最 大 流 , 相 同 方 式 判 断 。 所以再建图从t向s跑最大流,相同方式判断。 ts,

#include 
using namespace std;
#define id(x,y) (x-1)*m+y
const int maxn=2e5+10;
const int inf=1e9;
int n,m,s,t,yin[maxn];
int dis[maxn];
char a[109][109];
struct edge{
	int to,nxt,flow;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v,int flow){
	d[++cnt]=(edge){v,head[u],flow},head[u]=cnt;
	d[++cnt]=(edge){u,head[v],0},head[v]=cnt;
}
bool bfs(int s,int t)
{
	memset(dis,0,sizeof(dis));
	dis[s]=1;
	queueq; q.push( s );
	while( !q.empty() )
	{
		int u=q.front(); q.pop();
		for(int i=head[u];i;i=d[i].nxt )
		{
			int v=d[i].to;
			if( d[i].flow&&dis[v]==0 )
			{
				dis[v]=dis[u]+1;
				if( v==t )	return true;
				q.push( v );
			}
		}
	}
	return false;
}
int dinic(int u,int t,int flow)
{
	if( u==t )	return flow;
	int res=flow;
	for(int i=head[u];i&&res;i=d[i].nxt )
	{
		int v=d[i].to;
		if( dis[v]==dis[u]+1&&d[i].flow)
		{
			int temp=dinic(v,t,min(res,d[i].flow) );
			if( temp==0 )	dis[v]=0;
			res-=temp;
			d[i].flow-=temp;
			d[i^1].flow+=temp;
		}
	}
	return flow-res;
}
typedef pairp;
vector

vec; int main() { cin >> n >> m; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin >> a[i][j]; s=0,t=n*m+1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if( a[i][j]=='#' ) continue; if( (i+j)&1 ) add(s,id(i,j),1); else add(id(i,j),t,1); yin[id(i,j)]=cnt-1; if( i>1&&a[i-1][j]=='.' ) { if( (i+j)&1 ) add(id(i,j),id(i-1,j),1); else add(id(i-1,j),id(i,j),1); } if( j>1&&a[i][j-1]=='.' ) { if( (i+j)&1 ) add(id(i,j),id(i,j-1),1); else add(id(i,j-1),id(i,j),1); } } int ans=0; while( bfs(s,t) ) ans+=dinic(s,t,inf); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if( a[i][j]=='#' ) continue; if( (i+j)&1 ) { if( dis[id(i,j)]==0&&d[yin[id(i,j)]].flow==0 ) continue;//在最大匹配的充要条件 else vec.push_back(p(i,j));//只要有可能不在最大匹配,就可以赢 } } for(int i=2;i<=cnt;i+=2) d[i^1].flow+=d[i].flow,d[i].flow=0; while( bfs(t,s) ) ans+=dinic(t,s,inf); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if( a[i][j]=='#' ) continue; if( (i+j)&1 ) continue; else { if( dis[id(i,j)]==0&&d[yin[id(i,j)]+1].flow==0 ) continue;//在最大匹配的充要条件 else vec.push_back(p(i,j));//只要有可能不在最大匹配,就可以赢 } } cout << vec.size() << endl; sort(vec.begin(),vec.end()); for(int i=0;i

你可能感兴趣的:(网络流24题)