zoukankan      html  css  js  c++  java
  • POJ-2226 Muddy Fields---二分图匹配+巧妙构图

    题目链接:

    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 }
  • 相关阅读:
    小学生双倍快乐
    暑期随笔
    akm
    设计原型
    测试与优化
    小学生求求你别折磨程序员
    小学生快乐刷题
    枪在手,跟我走

    第一次团队作业
  • 原文地址:https://www.cnblogs.com/fzl194/p/8838654.html
Copyright © 2011-2022 走看看