传送门

其实换汤不换药

还是一行只能匹配一列

但是如果被一个块隔开,那么一行就能当两行用

所以根据块把行,列重新编号

跑二分图匹配即可

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;
int n,m,row[19][19],col[19][19];
char a[19][19];
struct edge{
	int to,nxt;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v){
	d[++cnt] = (edge){v,head[u]},head[u] = cnt;
}
int match[maxn],used[maxn];
bool find(int x)
{
	for(int i=head[x];i;i=d[i].nxt )
	{
		int v = d[i].to;
		if( used[v] )	continue;
		used[v] = 1;
		if( match[v]==0||find( match[v]) )
		{
			match[v] = x;
			return true;
		}
	}
	return false;
}
int main()
{
	while( cin >> n && n )
	{
		for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			cin >> a[i][j];
		int hang = 1; 
		for(int i=1;i<=n;i++)
		{
			a[i][0]='X';
			for(int j=1;j<=n;j++)
			{
				if( a[i][j]=='.'&&a[i][j-1]=='X' )	hang++;
				if( a[i][j]=='.' )	row[i][j] = hang;
			}
		}
		int lie = hang+1;
		for(int j=1;j<=n;j++)
		{
			a[0][j]='X';
			for(int i=1;i<=n;i++)
			{
				if( a[i][j]=='.'&&a[i-1][j]=='X' )	lie++;
				if( a[i][j]=='.' )	col[i][j] = lie;
			}
		}
		for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)	
			if( a[i][j]=='.' )	add( row[i][j],col[i][j] );
		int ans = 0;
		for(int i=1;i<=hang;i++)
		{
			memset( used,0,sizeof(used) );
			if( find(i) )	ans++;
		}
		cout << ans << endl;
		cnt = 1;
		for(int i=1;i<=hang;i++)	head[i] = 0;
		memset( match,0,sizeof(match) );
	}
}