POJ3020 二分图最小覆盖边问题——匈牙利算法
算法背景
匈牙利算法可以解决二分图的以下几个问题:https://blog.csdn.net/lzyws739307453/article/details/83040922
题目分析
看了discuss恍然大悟,建图可以把图染成一个国际象棋棋盘,黑色区域和白色区域是不能互通的,也就是说黑色区域和白色区域可以视为二分图的两部,问题就转化成二分图的最小边覆盖问题
代码
#include<iostream>
#include<string.h>
using namespace std;
const int MAXN = 550;
const int MAXM = 50;
int n,h,w,N;
int mat[MAXN][MAXN],vis[MAXN],match[MAXN];
char mat1[MAXM][MAXM];
int xx[4] = {1,-1,0,0},yy[4] ={0,0,1,-1};
bool check(int x,int y){
return(x>=1&&x<=h&&y>=1&&y<=w&&mat1[x][y]=='*');
}
int dfs(int x){
for(int i = 1;i <= MAXN;i++){
if(mat[x][i] && !vis[i]){
vis[i] = 1;
if(match[i]==-1||dfs(match[i])){
match[i] = x;
return 1;
}
}
}
return 0;
}
int main(){
cin>>n;
while(n--){
cin>>h>>w;
N = 0;
memset(mat,0,sizeof(mat));
memset(mat1,0,sizeof(mat1));
memset(match,-1,sizeof(match));
for(int i = 1;i <= h;i++)
for(int j = 1;j <= w;j++){
cin>>mat1[i][j];
if(mat1[i][j]=='*')N++;
}
for(int i = 1;i <= h;i++)
for(int j = 1;j <= w;j++){
if(((i%2==0&&j%2==0)||(i%2==1&&j%2==1))&&mat1[i][j]=='*'){
for(int k = 0;k < 4;k++){
if(check(i+xx[k],j+yy[k])){
mat[(i*w-w+j)/2+(i*w-w+j)%2][(i+xx[k])*w-w+j+yy[k]] = 1;
}
}
}
}
int cnt = 0;
for(int i = 1;i <= MAXN;i++){
memset(vis,0,sizeof(vis));
if(dfs(i)) cnt++;
}
cout<<N-cnt<<endl;
}
}
1840K 16MS