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

时间:2021-02-07 06:14:34

题目链接:

https://vjudge.net/problem/POJ-2226

题目大意:

用宽度为1长度不限的木板将水洼‘*’盖住而不盖住草‘.'

Sample Input

4 4
*.*.
.***
***.
..*.

Sample Output

4

解题思路:

这道题的构图方法十分巧妙,如果有连续的水洼,假设是横排的,那么这几个连续的水洼可以拿一个板子来覆盖,同样,如果竖排也有连续的水洼,那么也可以拿一个板子来覆盖。这样,当一个水洼既可以拿横着的板子,也可以拿竖着的板子覆盖时,就是相交了。那么这个交线就代表了一个水洼,它既可以被横着盖,也可以被竖着盖。现在我们把所有横排的水洼作为1个水洼需要1个木板,竖着的也同理。

有两种覆盖的方法,一种为横着盖一种为竖着盖覆盖后可转化为下图形式

横着盖:(图中数字表示用的是第几块木板)
1.2.
.333
444.
. . 5.
将这些点加入到X序列中
 
竖着盖:
1.2.
.324
532.
. . 2.
将这些点加入到Y序列中
 
将图中水洼进行编号一共有九个水洼
1.2.
.345
678.
. . 9.
9号水洼(5, 2)表示九号水洼可由横着的5号木板覆盖也可以由竖着的2号木板覆盖,5号木板和2号木板之间就有一条线
这样就组成一个二分图,最后求最小的顶点覆盖。就是等于保证每个泥地都被横着的木板或者竖着的木板覆盖了。
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<vector>
 5 using namespace std;
 6 const int maxn = 2500 + 10;
 7 
 8 int cx[maxn], cy[maxn];
 9 bool vis[maxn];
10 vector<int>G[maxn];
11 int x, y;
12 //x表示二分图X部的点数
13 //y表示二分图Y部的点数
14 bool dfs(int u)
15 {
16     for(int i = 0; i < G[u].size(); i++)
17     {
18         int v = G[u][i];
19         if(!vis[v])//如果该点还没进入增广路
20         {
21             vis[v] = 1;//加入增广路
22             if(cy[v] == -1 || dfs(cy[v]))
23             {
24                 cx[u] = v;
25                 cy[v] = u;
26                 return 1;
27             }
28         }
29     }
30     return 0;
31 }
32 
33 int maxmatch()
34 {
35     int ans = 0;
36     memset(cx, -1, sizeof(cx));
37     memset(cy, -1, sizeof(cy));
38     for(int i = 1; i <= x; i++)
39     {
40         if(cx[i] == -1)
41         {
42             memset(vis, 0, sizeof(vis));
43             ans += dfs(i);
44         }
45     }
46     return ans;
47 }
48 char Map[55][55];
49 int cnt[55][55], n, m;
50 void Build()//建图巧妙
51 {
52     int a[55][55], b[55][55];
53     memset(a, 0, sizeof(a));
54     memset(b, 0, sizeof(b));
55     //木板横着放
56     x = 0, y = 0;
57     for(int i = 0; i < n; i++)
58     {
59         for(int j = 0; j < m; j++)
60         {
61             if(Map[i][j] == '*')
62             {
63                 if(Map[i][j - 1] == '*')
64                     a[i][j] = a[i][j - 1];
65                 else a[i][j] = ++x;
66             }
67         }
68     }
69     //木板竖着放
70     for(int j = 0; j < m; j++)
71     {
72         for(int i = 0; i < n; i++)
73         {
74             if(Map[i][j] == '*')
75             {
76                 if(Map[i - 1][j] == '*')
77                     b[i][j] = b[i - 1][j];
78                 else b[i][j] = ++y;
79                 //cout<<a[i][j]<<" "<<b[i][j]<<endl;
80                 //建边
81                 G[a[i][j]].push_back(b[i][j]);
82             }
83         }
84     }
85 }
86 int main()
87 {
88     cin >> n >> m;
89     for(int i = 0; i < n; i++)
90     {
91         cin >> Map[i];
92     }
93     Build();
94     cout<<maxmatch()<<endl;
95     return 0;
96 }