• UVA 11419SAM I AM(输出 最小覆盖点 )


    参考博客:如何找取 最小覆盖点集合

    题意:R*C大小的网格,网格上面放了一些目标。可以再网格外发射子弹,子弹会沿着垂直或者水平方向飞行,并且打掉飞行路径上的所有目标,计算最小多少子弹,各从哪些位置发射,才能将所有的目标全部打掉

    分析:就是求最小覆盖点 以及 输出所有的覆盖点

    最小覆盖点 == 最大匹配数

    个人理解:

    最大匹配数是用匈牙利算法求的,就是从左边一个点开始找到他看上的那个妹纸,如果那个妹纸已经名花有有主就跟那个男生换一个...沿着 ( 没匹配 - 匹配边 -... - 没匹配边)  这样的增广路径来探寻。

    假设已经求得最大匹配,怎么证明最大匹配等于最小覆盖点呢, 首先从左边没有匹配上的边开始 找增光路,找到所有的点都标记一下,当然不会找到一个全的,如果全的话就不是最大匹配,又多出来一个匹配边。  那么最小覆盖点就是 左边 没标记 + 右边标记的, 为什么呢? 对于左边没标记的 也就是说他有 匹配边 同时与他相连的右边那个点 没被标记,(如果右边标记, 他就被标记了),所有左边 所有没标记的点 是 最大匹配边的一部分 , 然后右边标记的呢,从左边没标记点开始连向右边的点,右边的这个点一定被匹配上了的,右边标记的点也是匹配边的一个端点,组成了 最大匹配边的那一部分,  说白点就是 左边没标记的匹配边 就是这两个点就是相互喜欢型的,而右边标记的就是有别人暗恋的。

     1 #include <iostream>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <cstdio>
     5 #include <vector>
     6 using namespace std;
     7 const int Max = 1000 + 10;
     8 int n, m;
     9 vector<int> G[Max];
    10 int Left[Max], Right[Max]; // left[i]表示右边的i对应左边的编号,right[i]表示左边的i对应右边的编号
    11 bool vis[Max];  // 右边的点有没有访问
    12 bool S[Max];  // 左边的点有没有没标记
    13 void init()
    14 {
    15     for (int i = 0; i < n; i++)
    16         G[i].clear();
    17 }
    18 void addedge(int u, int v)
    19 {
    20     G[u].push_back(v);
    21 }
    22 bool mach(int u)
    23 {
    24     S[u] = true;
    25     int len = (int) G[u].size();
    26     for (int i = 0; i < len; i++)
    27     {
    28         int v = G[u][i];
    29         if (!vis[v])
    30         {
    31             vis[v] = true;
    32             if (Left[v] == -1 || mach(Left[v]))
    33             {
    34                 Left[v] = u;  // 存储匹配关系
    35                 Right[u] = v;
    36                 return true;
    37             }
    38         }
    39     }
    40     return false;
    41 }
    42 int solve()
    43 {
    44     memset(Left, -1, sizeof(Left));
    45     memset(Right, -1, sizeof(Right));
    46     int ans = 0;
    47     for (int i = 0; i < n; i++)
    48     {
    49         memset(vis, 0, sizeof(vis));
    50         if (mach(i))
    51             ans++;
    52     }
    53     return ans;
    54 }
    55 int mincover(vector<int> & X, vector<int> & Y)
    56 {
    57     int ans = solve();
    58     memset(vis, 0, sizeof(vis));
    59     memset(S, 0, sizeof(S));
    60     for (int i = 0; i < n; i++)
    61     {
    62         if (Right[i] == -1)  // 从左边没有匹配的点开始找增广路
    63             mach(i);
    64     }
    65     for (int i = 0; i < n; i++)
    66         if (!S[i])    // 左边没标记
    67             X.push_back(i);
    68     for (int i = 0; i < m; i++)
    69         if (vis[i])   // 右边标记的
    70             Y.push_back(i);
    71     return ans;
    72 }
    73 int main()
    74 {
    75     int c, r, N;
    76     while (scanf("%d%d%d", &n, &m, & N) != EOF)
    77     {
    78         if (n == 0 && m == 0 && N == 0)
    79             break;
    80         init();
    81         for (int i = 0; i < N; i++)
    82         {
    83             scanf("%d%d", &r, &c);
    84             r--;
    85             c--;
    86             addedge(r, c);
    87         }
    88         vector<int> X, Y;
    89         int ans = mincover(X, Y);
    90         printf("%d", ans);
    91         for (int i = 0; i < (int) X.size(); i++)
    92             printf(" r%d", X[i] + 1);
    93         for (int j = 0; j < (int) Y.size(); j++)
    94             printf(" c%d", Y[j] + 1);
    95         printf("
    ");
    96     }
    97 
    98     return 0;
    99 }
    View Code
  • 相关阅读:
    linux下/proc/sysrq-trigger文件的功能
    Windows下bat命令
    转——802.11协议
    转 ——eclipse下进行Python开发 环境配置
    U盘装centos7系统过程
    django框架介绍
    2-事件之间关系(概率论与数理统计学记笔记)
    1-基本概念(概率论与数理统计学习笔记)
    舆情正负面判断

  • 原文地址:https://www.cnblogs.com/zhaopAC/p/5375122.html
Copyright © 2020-2023  润新知