POJ2226 Muddy Fields 二分匹配 最小顶点覆盖 好题

在一个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 }

时间: 2024-11-03 22:14:19

POJ2226 Muddy Fields 二分匹配 最小顶点覆盖 好题的相关文章

POJ2226 Muddy Fields(二分图最小点覆盖集)

题目给张R×C的地图,地图上*表示泥地..表示草地,问最少要几块宽1长任意木板才能盖住所有泥地,木板可以重合但不能盖住草地. 把所有行和列连续的泥地(可以放一块木板铺满的)看作点且行和列连续泥地分别作为XY部,每一块泥地看作边.这样就构造出了一个二分图. 那么,问题就是在这个二分图中就是选出最少的点覆盖所有的边,即二分图最小点覆盖集,而二分图最小点覆盖集=二分图最大匹配. 1 #include<cstdio> 2 #include<cstring> 3 #include<qu

POJ2226 Muddy Fields【二分图最小点覆盖】

题目链接: http://poj.org/problem?id=2226 题目大意: 有一个r行c列的方格组成的田地.里边有若干个方格充满泥水,其余的方格是草.要用宽度为1.长度 不限的长木板把充满泥水的方格覆盖掉,但不能覆盖草地,同时只能按行覆盖或是按列覆盖,不能斜着 覆盖.问:最少要用多少木板. 思路: 这道题感觉很难想.看了看网上的题解,居然很巧妙的构造了二分图来求解,很是精妙.我们把同一行 一段连续的泥水方格作为一个顶点,把这些点作为二分图的一个集合,再把同一列一段连续的泥水方格 作为一

poj2226Muddy Fields 二分匹配之最小点覆盖

//给r*c的 field ,有的地方有水,用宽度为1,长度任意的木板将这些有水的地方, //遮住,木板可以相互叠加,木板不能遮住有草的地方 //可以每行中的连续的格子看成一个点xi,每一列中连续的格子看成一个点yj //将每一个有水的格子看成一条边连接对应的xi , yj //那么其最小点覆盖即为答案 #include<cstdio> #include<cstring> #include<iostream> using namespace std ; const in

POJ-2226 Muddy Fields---二分图匹配+巧妙构图

题目链接: https://vjudge.net/problem/POJ-2226 题目大意: 用宽度为1长度不限的木板将水洼'*'盖住而不盖住草'.' Sample Input 4 4 *.*. .*** ***. ..*. Sample Output 4 解题思路: 这道题的构图方法十分巧妙,如果有连续的水洼,假设是横排的,那么这几个连续的水洼可以拿一个板子来覆盖,同样,如果竖排也有连续的水洼,那么也可以拿一个板子来覆盖.这样,当一个水洼既可以拿横着的板子,也可以拿竖着的板子覆盖时,就是相交

POJ 1325 Machine Schedule(二分匹配 最小点覆盖)

题目链接:http://poj.org/problem?id=1325 Description As we all know, machine scheduling is a very classical problem in computer science and has been studied for a very long history. Scheduling problems differ widely in the nature of the constraints that m

POJ2226 Muddy Fields

原题链接 因为每一块泥地要么被横着的木板盖住,要么被竖着的木板盖住,所以可以转换为二分图最小点覆盖问题. 我们可以先标记出所有连续的行泥地和连续的列泥地. 比如对于原题中的样例,标记后是这样的: 行连续泥地:\(\begin{pmatrix}1 & 0 & 2 & 0 \\ 0 & 3 & 3 & 3 \\ 4 & 4 & 4 & 0 \\ 0 & 0 & 5 & 0 \end{pmatrix}\) 列连续泥地

hdu 4169 二分匹配最大独立集 ***

题意:有水平N张牌,竖直M张牌,同一方向的牌不会相交.水平的和垂直的可能会相交,求最少踢出去几张牌使剩下的牌都不相交. 二分匹配 最小点覆盖=最大匹配. 链接:点我 坐标点作为匹配的端点 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #incl

hdu1054(最小顶点覆盖)

传送门:Strategic Game 题意:用尽量少的顶点来覆盖所有的边. 分析:最小顶点覆盖裸题,最小顶点覆盖=最大匹配数(双向图)/2. #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <iostream> #include <algorithm> #include <queue> #include <

HDU 2063 过山车(二分匹配入门)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2063 二分匹配最大匹配数简单题,匈牙利算法.学习二分匹配传送门:http://blog.csdn.net/dark_scope/article/details/8880547 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 using nam