题意: 给出一个N*N的地图N 地图里面有K个障碍 你每次可以选择一条直线 消除这条直线上的所有障碍 (直线只能和列和行平行)
问最少要消除几次
题解: 如果(x,y)上有一个障碍 则把X加入点集 V1 、Y加入点集V2 并且X Y连一条边 这样构成一个新图
如果选择 V1中的点 X 那么就相当于消去 (X,y)中的所有Y 要找使最小点覆盖 那就是跑一遍 匈牙利就行了 详细证明见二分图最小点覆盖König定理
其中 x y需要连单向边 不然会造成混乱 因为x=1 y=1是不同的含义
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=;
int n,k;
int mp[maxn][maxn];
int girl[maxn];
int used[maxn];
bool find(int x){
int i,j;
for(j=;j<=n;j++){
if(mp[x][j]==&&used[j]==){
used[j]=;
if(girl[j]==||find(girl[j])){
girl[j]=x;
return ;
}
}
}
return ;
}
int main(){
cin>>n>>k;
for(int i=;i<=k;i++){
int a,b;
scanf("%d%d",&a,&b);//建边
mp[a][b]=;
}
int sum=;
for(int i=;i<=n;i++){
memset(used,,sizeof(used));//每次要初始化 因为used是用于判断之前有没有用过 什么叫之前有没用用过 比如进入3的递归,used[2]=1,3 和2匹配 2已经在之前已经有归属了 现在要进行拆边 find(girl(j)) 此时假设girl(j)=5,5就不能和2匹配了,因为现在进行拆边操作时逻辑上已经认定 上层递归的used[2]=1 已经用了2
if(find(i))sum++;
}
cout<<sum<<endl;
return ;
}