【bzoj 4554】【Tjoi2016&Heoi2016】【NOIP2016模拟7.12】游戏

分析

当没有石头的时候,就用二分图匹配来做。
但现在加入了石头,
所以,求出每行和每列联通快的个数,如果有一块平地,包括在某个行联通块以及某个列联通块中,连边。

//无聊打了网络流,匈牙利也可以
#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
const int mo=1000000007;
const int N=54;
using namespace std;
int n,m,a[N][N],ans,tot,f[N*N+6][N*N+6],id,v[N*N+6],t;
int b[N][N];
int aug(int x,int y)
{
	if(x==n*m+n) return y;
	v[x]=id;
	for(int i=0;i<=n*m+n;i++)
	{
		if(f[x][i] && v[i]<id)
		{
			int o=aug(i,min(y,f[x][i]));
			if(o)
			{
				f[x][i]-=o;
				f[i][x]+=o;
				return o;
			}
		}
	}
	return 0;
}							
int main()
{
	scanf("%d%d",&n,&m);
	tot=0;
	for(int i=1;i<=n;i++)
	{
		tot++;
		for(int j=1;j<=m;j++)
		{
			char c;
			c=getchar();
			while(c!='*' && c!='x' && c!='#') c=getchar();
			if(c=='*') a[i][j]=1;
			else
				if(c=='x') a[i][j]=2;
					else
						a[i][j]=3;
			if(a[i][j]==3 && a[i][j-1]!=3) tot++;
			else
			{
				f[0][tot]=1;
				b[i][j]=tot;
			}
		}
	}
	for(int i=1;i<=m;i++)
	{
		tot++;
		for(int j=1;j<=n;j++)
		{
			if(a[j][i]==3) tot++;
			else
			{
				if(a[j][i]!=2) f[b[j][i]][tot]=1;
				f[tot][n*m+n]=1;
			}
		}
	}
	t=1;
	while(t)
	{
		id++;
		t=aug(0,maxlongint);
		ans+=t;		
	}
	printf("%d",ans);
}

相关文章: