zoukankan      html  css  js  c++  java
  • POJ-3020 Antenna Placement---二分图匹配&最小路径覆盖&建图

    题目链接:

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

    题目大意:

    一个n*m的方阵 一个雷达可覆盖两个*,一个*可与四周的一个*被覆盖,一个*可被多个雷达覆盖问至少需要多少雷达能把所有的*覆盖

    解题思路:

    把每个*城市编号,然后每相邻两个城市之间连线。这里求最少多少个雷达可以覆盖完*,就是二分图匹配中的最小路径覆盖数,但是这里的图的边是双向的。举个例子

    o*o

    **o

    ooo

    这里可以编号成

    010

    230

    000

    那么有边<1,3><3,1><2,3><3,2>

    按照二分图匹配建图的方法,每个点拆分成两个点A1,A2,如果有边<A, B>在二分图中建立边<A1, B2>。


    这里的特殊性在于1和3有边,3和1也有边,所以最后求出来的最大匹配需要除以2才是题目所需要的最大匹配

    最小路径覆盖数 = 顶点数 - 最大匹配

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #include<vector>
     6 #include<queue>
     7 using namespace std;
     8 typedef pair<int, int> Pair ;
     9 typedef long long ll;
    10 const int INF = 0x3f3f3f3f;
    11 const int maxn = 500 + 10;
    12 int T, n, m, cases;
    13 vector<int>G[maxn];
    14 int cx[maxn], cy[maxn];
    15 bool vis[maxn];
    16 char Map[50][50];
    17 int cnt[50][50], tot;
    18 int dir[4][2] = {1,0,0,1,-1,0,0,-1};
    19 bool dfs(int u)
    20 {
    21     for(int i = 0; i < G[u].size(); i++)
    22     {
    23         int v = G[u][i];
    24         if(!vis[v])
    25         {
    26             vis[v]  =1;//加入增广路
    27             if(cy[v] == -1 || dfs(cy[v]))
    28             {
    29                 cx[u] = v;
    30                 cy[v] = u;
    31                 return 1;
    32             }
    33         }
    34     }
    35     return 0;
    36 }
    37 
    38 int maxmatch()
    39 {
    40     int ans = 0;
    41     memset(cx, -1, sizeof(cx));
    42     memset(cy, -1, sizeof(cy));
    43     for(int i = 1; i <= tot; i++)
    44     {
    45         if(cx[i] == -1)
    46         {
    47             memset(vis, 0, sizeof(vis));
    48             ans += dfs(i);
    49         }
    50     }
    51     return ans;
    52 }
    53 
    54 int main()
    55 {
    56     cin >> T;
    57     while(T--)
    58     {
    59         scanf("%d%d", &n, &m);
    60         tot = 0;
    61         for(int i = 0; i < maxn; i++)G[i].clear();
    62         for(int i = 0; i < n; i++)//将Map转化成城市的编号
    63         {
    64             cin >> Map[i];
    65             for(int j = 0; j < m ;j++)
    66                 if(Map[i][j] == 'o')cnt[i][j] = 0;
    67                 else cnt[i][j] = ++tot;
    68         }/*
    69         for(int i = 0; i < n; i++)
    70         {
    71             for(int j = 0; j < m; j++)cout<<cnt[i][j]<<" ";
    72             cout<<endl;
    73         }*/
    74         for(int i = 0; i < n; i++)
    75         //二分图建图,每个点拆成两个点,建成有向图,并且每两点之间有两条相反边,所以求出来的最大匹配是真正匹配的两倍
    76         {
    77             for(int j = 0; j < m; j++)
    78             {
    79                 if(!cnt[i][j])continue;
    80                 for(int k = 0; k < 4; k++)
    81                 {
    82                     int xx = i + dir[k][0];
    83                     int yy = j + dir[k][1];
    84                     if(!cnt[xx][yy])continue;
    85                     if(xx < 0 || xx >= n || yy < 0 || yy >= m)continue;
    86                     int u = cnt[i][j], v = cnt[xx][yy];
    87                     //cout<<u<<" "<<v<<endl;
    88                     G[u].push_back(v);
    89                 }
    90             }
    91         }
    92         //最小路径覆盖数 = 顶点数 - 最大匹配数
    93         int ans = tot - maxmatch() / 2;
    94         cout<<ans<<endl;
    95     }
    96     return 0;
    97 }
  • 相关阅读:
    linux抓包命令tcpdump
    Linux ssh配置详解
    吞吐量(TPS)、QPS、并发数、响应时间(RT)概念
    Python装饰器详解
    centos7 安装redis
    C# 操作Exchange 的powershell以实现邮件撤回
    C# 委托的理解和案例
    IIS10 http重定向https
    程序员修炼之道 | 不要让你的代码走上渡渡鸟的灭绝之路
    离子烫攻略
  • 原文地址:https://www.cnblogs.com/fzl194/p/8836430.html
Copyright © 2011-2022 走看看