题意:一个由r行c列方格组成的田地,里面有若干个方格充满泥泞,其余方格都是草。要用长度不限,宽度为1的长木板来覆盖这些泥方格,但不能覆盖草地。最少要用多少个长木板?
分析:由于不能覆盖草地,这道题显得相当难。看别人的题解看了很久才明白它是如何跟二分匹配联系在一起的。这个建图实在是精妙。我们先把同一行每一段连续的泥方格作为一个顶点(其实就是一个长木板),这些顶点放进去集合x;而同一列每一段连续的泥方格也作为一个顶点,放进集合y。a∈x,b∈y,a,b若有相交则建一条边(a,b)。巧妙之处就在这条边,每条边所表示的就是原来的图中的一个泥方格,边与泥方格存在一一对应关系。若选了a(a∈x或a∈y)木板,则所有与a关联的边所表示的泥方格都会被覆盖。所以现在的问题就变成,求这个二分图的最小点覆盖数。由公式:最小点覆盖数=最大匹配数,即可知只要求最大匹配就OK。
另外,这道题坑爹之处是,图的大小不止50*50
View Code
1 #include<cstdio> 2 bool matrix[500][500],visited[500]; 3 char map[501][501]; 4 int r,c,mat[2][500],set[500][500],nx,ny; 5 int path(int u) 6 { 7 int i; 8 for(i=0;i<ny;i++) 9 { 10 if(matrix[u][i] && !visited[i]) 11 { 12 visited[i]=true; 13 if(mat[1][i]==-1 || path(mat[1][i])) 14 { 15 mat[0][u]=i; 16 mat[1][i]=u; 17 return 1; 18 } 19 } 20 } 21 return 0; 22 } 23 int Hungary() 24 { 25 int ans=0,i,j; 26 for(i=0;i<nx;i++) 27 mat[0][i]=-1; 28 for(i=0;i<ny;i++) 29 mat[1][i]=-1; 30 for(i=0;i<nx;i++) 31 { 32 for(j=0;j<ny;j++) 33 visited[j]=false; 34 ans+=path(i); 35 } 36 return ans; 37 } 38 int main() 39 { 40 int i,j; 41 while(~scanf("%d%d%*c",&r,&c)) 42 { 43 for(i=0;i<r;i++) 44 { 45 for(j=0;j<c;j++) 46 matrix[i][j]=false; 47 } 48 for(i=0;i<r;i++) 49 gets(map[i]); 50 nx=0; 51 for(i=0;i<r;i++) 52 { 53 for(j=0;j<c;j++) 54 { 55 if(map[i][j]=='*') 56 { 57 while(j<c && map[i][j]=='*') 58 set[i][j++]=nx; 59 nx++; 60 } 61 } 62 } 63 ny=0; 64 for(j=0;j<c;j++) 65 { 66 for(i=0;i<r;i++) 67 { 68 if(map[i][j]=='*') 69 { 70 while(i<r && map[i][j]=='*') 71 matrix[set[i++][j]][ny]=true; 72 ny++; 73 } 74 } 75 } 76 printf("%d\n",Hungary()); 77 } 78 return 0; 79 }