这个题还是属于二分匹配
普通的二分匹配就是把边和列分别变成二分匹配中两边的点,两边点之间的线代表了图中该点是否可选择
这个相当于为边和列加上了屏障 我们可以扩行和扩列
如果存在X把行分成了两部分 那我们把边分成两份(我这里的操作是令mp[i+n][j]=1)
列相同
(相当于我把地图从n*n扩展成了2n*2n)
#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;
int n;
char m[10][10];
int col[20];
int row[20];
int mp[20][20];
int k = 0;
int used[20];
int linker[20];
bool dfs(int u){
for(int i = 0;i<2*n;++i){
if(mp[u][i]&&!used[i]){
used[i] = 1;
if(linker[i]==-1||dfs(linker[i])){
linker[i] = u;
return true;
}
}
}
return false;
}
int hungry(){
memset(linker,-1,sizeof(linker));
int res = 0;
for(int i =0;i<2*n;++i){
memset(used,0,sizeof(used));
if(dfs(i))
res++;
//cout<<linker[i]<<":"<<i<<endl;
}
return res;
}
int main(){
while(~scanf("%d",&n)&&n){
memset(m,'\0',sizeof(m));
memset(mp,0,sizeof(mp));
for(int i =0;i<n;++i){
scanf("%s",m[i]);
}
k =0;
for(int i =0;i<n;++i){
int flag = 0;
int flag1 = 0;
for(int j =0;j<n;++j){
if(m[i][j]=='.'&&flag==1){
flag = 0;
mp[n+i][j]=1;
}
else if(m[i][j]=='.'&&flag==0){
mp[i][j]=1;
// cout<<i<<":"<<j<<endl;
}
else if(m[i][j]=='X'){
flag = 1;
}
if(m[j][i]=='.'&&flag1==1){
flag1 = 0;
mp[j][i+n]=1;
}
else if(m[j][i]=='.'&&flag1==0){
mp[j][i]=1;
// cout<<i<<":"<<j<<endl;
}
else if(m[j][i]=='X'){
flag1 = 1;
}
}
k++;
}
cout<<hungry()<<endl;
}
}