标签:
在一个n*m的草地上,.代表草地,*代表水,现在要用宽度为1,长度不限的木板盖住水,
木板可以重叠,但是所有的草地都不能被木板覆盖。
问至少需要的木板数。
这类题的建图方法:
把矩阵作为一个二分图,以行列分别作为2个顶点集
首先以每一行来看,把这一行里面连续的*编号,作为一个顶点
再以每一列来看,把这一列里面连续的*编号,作为一个顶点
则每一个*都有2个编号,以行看时有一个,以列看时有一个,则把这2个编号连边,容量为1
再建一个源点,连接所有行的编号,一个汇点,连接所有列的编号
这道题要求的是,所有*都被覆盖,即找到一个顶点的集合S,使得任意边都有至少一个顶点属于
S,即求一个点集顶点覆盖S,又要木板数最少,所以求的就是最小顶点覆盖。
最小顶点覆盖怎么求?
二分图中,有:
最小顶点覆盖=最大匹配
所以这道题就转化为求二分图的最大匹配了
再转化为最大流dinic算法。
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<queue> 5 6 using namespace std; 7 8 const int maxn=2510; 9 const int inf=0x3f3f3f3f; 10 const int s=0; 11 int t; 12 int tota; 13 int totb; 14 15 inline int min(int x,int y) 16 { 17 return x<y?x:y; 18 } 19 20 struct Edge 21 { 22 int to,cap,rev; 23 }; 24 vector<Edge>edge[maxn]; 25 int iter[maxn]; 26 int level[maxn]; 27 char str[55][55]; 28 int hash[55][55]; 29 30 void addedge(int from,int to,int cap) 31 { 32 edge[from].push_back((Edge){to,cap,edge[to].size()}); 33 edge[to].push_back((Edge){from,0,edge[from].size()-1}); 34 } 35 36 void build_graph(int n,int m) 37 { 38 for(int i=0;i<n*m;i++) 39 edge[i].clear(); 40 tota=0; 41 for(int i=1;i<=n;i++) 42 { 43 int j=1; 44 while(j<=m) 45 { 46 if(str[i][j]==‘*‘) 47 { 48 tota++; 49 hash[i][j]=tota; 50 while(j<=m&&str[i][j+1]==‘*‘) 51 { 52 j++; 53 hash[i][j]=tota; 54 } 55 } 56 j++; 57 } 58 } 59 totb=tota; 60 for(int j=1;j<=m;j++) 61 { 62 int i=1; 63 while(i<=n) 64 { 65 if(str[i][j]==‘*‘) 66 { 67 totb++; 68 addedge(hash[i][j],totb,1); 69 while(i<=n&&str[i+1][j]==‘*‘) 70 { 71 i++; 72 addedge(hash[i][j],totb,1); 73 } 74 } 75 i++; 76 } 77 } 78 t=tota+totb+1; 79 for(int i=1;i<=tota;i++) 80 addedge(s,i,1); 81 for(int i=tota+1;i<=totb;i++) 82 addedge(i,t,1); 83 } 84 85 void bfs() 86 { 87 memset(level,-1,sizeof level); 88 queue<int>que; 89 while(!que.empty()) 90 que.pop(); 91 que.push(s); 92 level[s]=1; 93 while(!que.empty()) 94 { 95 int u=que.front(); 96 que.pop(); 97 for(int i=0;i<edge[u].size();i++) 98 { 99 Edge &e=edge[u][i]; 100 if(e.cap>0&&level[e.to]<0) 101 { 102 level[e.to]=level[u]+1; 103 que.push(e.to); 104 } 105 } 106 } 107 } 108 109 int dfs(int u,int f) 110 { 111 if(u==t) 112 return f; 113 for(int &i=iter[u];i<edge[u].size();i++) 114 { 115 Edge &e=edge[u][i]; 116 if(e.cap>0&&level[e.to]>level[u]) 117 { 118 int d=dfs(e.to,min(f,e.cap)); 119 if(d>0) 120 { 121 e.cap-=d; 122 edge[e.to][e.rev].cap+=d; 123 return d; 124 } 125 126 } 127 } 128 return 0; 129 } 130 131 int solve() 132 { 133 int flow=0; 134 while(true) 135 { 136 bfs(); 137 if(level[t]<0) 138 return flow; 139 memset(iter,0,sizeof iter); 140 int f; 141 while(f=dfs(s,inf)) 142 { 143 flow+=f; 144 } 145 } 146 } 147 148 int main() 149 { 150 int n,m; 151 while(~scanf("%d%d",&n,&m)) 152 { 153 for(int i=1;i<=n;i++) 154 { 155 scanf("%s",str[i]+1); 156 } 157 build_graph(n,m); 158 printf("%d\n",solve()); 159 } 160 return 0; 161 }
POJ2226 Muddy Fields 二分匹配 最小顶点覆盖 好题
标签:
原文地址:http://www.cnblogs.com/-maybe/p/4716460.html