题意:经典的二分图匹配问题。给出一个N*N矩阵,其中有K个障碍物。一发歼星炮可以清楚一行或者一列上的障碍物。求最少的开炮数。
做法:可以考虑最大点覆盖。建图左边顶点为行,右边顶点为列。若有障碍物则连边。此时最大点覆盖就是最小开炮数,也就是计算二分图最大匹配。使用匈牙利算法即可。
1 /*--------------------------------------------------------------------------------------*/ 2 // Helica's header 3 // Second Edition 4 // 2015.11.7 5 // 6 #include <algorithm> 7 #include <iostream> 8 #include <cstring> 9 #include <ctype.h> 10 #include <cstdlib> 11 #include <cstdio> 12 #include <vector> 13 #include <string> 14 #include <queue> 15 #include <stack> 16 #include <cmath> 17 #include <set> 18 #include <map> 19 20 //debug function for a N*M array 21 #define debug_map(N,M,G) printf("\n");for(int i=0;i<(N);i++)\ 22 {for(int j=0;j<(M);j++){\ 23 printf("%d",G[i][j]);}printf("\n");} 24 //debug function for int,float,double,etc. 25 #define debug_var(X) cout<<#X"="<<X<<endl; 26 /*--------------------------------------------------------------------------------------*/ 27 using namespace std; 28 29 const int maxn = 500+10; 30 int uN,vN; 31 int G[2*maxn][2*maxn],linker[maxn]; 32 bool used[maxn]; 33 34 bool dfs(int u) 35 { 36 for(int v=1;v<=vN;v++) 37 { 38 if(G[u][v]&& !used[v]) 39 { 40 used[v] = true; 41 if(linker[v] == -1 || dfs(linker[v])) 42 { 43 linker[v] = u; 44 return true; 45 } 46 } 47 } 48 return false; 49 } 50 51 int hungary() 52 { 53 int res = 0; 54 memset(linker,-1,sizeof linker); 55 for(int u=1;u<=uN;u++) 56 { 57 memset(used,false,sizeof(used)); 58 if(dfs(u)) res++; 59 } 60 return res; 61 } 62 63 int N,K,M,T; 64 65 int main() 66 { 67 while(~scanf("%d%d",&N,&K)) 68 { 69 memset(G,0,sizeof G); 70 uN = vN = N; 71 for(int i=0;i<K;i++) 72 { 73 int x,y; 74 scanf("%d%d",&x,&y); 75 G[x][y] = 1; 76 } 77 printf("%d\n",hungary()); 78 } 79 }