Asteroids POJ - 3041 匈牙利算法+最小点覆盖König定理
题意: 给出一个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是不同的含义
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 const int maxn=1000; 6 int n,k; 7 int mp[maxn][maxn]; 8 int girl[maxn]; 9 int used[maxn]; 10 bool find(int x){ 11 int i,j; 12 for(j=1;j<=n;j++){ 13 if(mp[x][j]==1&&used[j]==0){ 14 used[j]=1; 15 if(girl[j]==0||find(girl[j])){ 16 girl[j]=x; 17 return 1; 18 } 19 } 20 } 21 return 0; 22 } 23 int main(){ 24 cin>>n>>k; 25 for(int i=1;i<=k;i++){ 26 int a,b; 27 scanf("%d%d",&a,&b);//建边 28 mp[a][b]=1; 29 } 30 int sum=0; 31 for(int i=1;i<=n;i++){ 32 memset(used,0,sizeof(used));//每次要初始化 因为used是用于判断之前有没有用过 什么叫之前有没用用过 比如进入3的递归,used[2]=1,3 和2匹配 2已经在之前已经有归属了 现在要进行拆边 find(girl(j)) 此时假设girl(j)=5,5就不能和2匹配了,因为现在进行拆边操作时逻辑上已经认定 上层递归的used[2]=1 已经用了2 33 if(find(i))sum++; 34 } 35 cout<<sum<<endl; 36 return 0; 37 }