​传送门​

其实换汤不换药

还是一行只能匹配一列

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

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

跑二分图匹配即可

#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) );
}
}