zoukankan      html  css  js  c++  java
  • UVA11419 SAM I AM 二分图最小点覆盖

    题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2414

    Solution

    看到求最小大炮轰的次数我们很容易想到二分图的最小点覆盖,就是求最少哪些行或者列开出炮弹可以使得全部怪物被打死掉,那么我们行列建图,求一个最大匹配就行了

    数据范围匈牙利即可,跑完一个最大匹配后,得到了数字答案,那么问题来了,如何得到在哪些行或者列打出炮弹呢。

    我们结合图上来看

    对于这个图,我们跑完匈牙利匹配后,1和2有连接,3和3有连接,我们输出应该是c2,r3/c3

    可以这样想,左边已经匹配完成的点不管它,我们把左边没有匹配的点重新匹配,这时候重新被访问的左端节点就是不能开出炮弹的行(有更优的列值)

    怎么说呢,我们看图模拟一边,首先左点2没有连接,从它开始匹配,找到右2,右2已经有匹配左点1,试图给左1分配一个新的点,然而没有,增广失败,

    这次寻找增广路我们从左2找到了右2再到左1终止,那这时就把左点1,2加入不可开炮队列,而将右点2加入可开炮队列(因为右点2可以一枪打死俩,更加优秀)

    而重新访问到的右点则是需要开出炮弹的列,这种情况在上图没有出现,和上面讨论类似。

      1 /*
      2     最小点覆盖+找出最小点覆盖的点集
      3  */
      4 #include <bits/stdc++.h>
      5 #define lson rt << 1, l, mid
      6 #define rson rt << 1 | 1, mid + 1, r
      7 using namespace std;
      8 using ll = long long;
      9 using ull = unsigned long long;
     10 using pa = pair<int, int>;
     11 using ld = long double;
     12 int n, m, k;
     13 const int maxn = 1e3 + 10;
     14 template <class T>
     15 inline T read(T &ret)
     16 {
     17     int f = 1;
     18     ret = 0;
     19     char ch = getchar();
     20     while (!isdigit(ch))
     21     {
     22         if (ch == '-')
     23             f = -1;
     24         ch = getchar();
     25     }
     26     while (isdigit(ch))
     27     {
     28         ret = (ret << 1) + (ret << 3) + ch - '0';
     29         ch = getchar();
     30     }
     31     ret *= f;
     32     return ret;
     33 }
     34 template <class T>
     35 inline void write(T n)
     36 {
     37     if (n < 0)
     38     {
     39         putchar('-');
     40         n = -n;
     41     }
     42     if (n >= 10)
     43     {
     44         write(n / 10);
     45     }
     46     putchar(n % 10 + '0');
     47 }
     48 int llink[maxn], rlink[maxn], visl[maxn], visr[maxn];
     49 vector<int> g[maxn];
     50 inline void init()
     51 {
     52     memset(llink, -1, sizeof(int) * (m + 2));
     53     memset(rlink, -1, sizeof(int) * (n + 2));
     54     for (int i = 1; i <= n; i++)
     55         g[i].clear();
     56 }
     57 inline void add(int x, int y)
     58 {
     59     g[x].emplace_back(y);
     60 }
     61 int find(int u)
     62 {
     63     visl[u] = 1;
     64     int sz = g[u].size();
     65     for (int i = 0; i < sz; i++)
     66     {
     67         int v = g[u][i];
     68         if (!visr[v])
     69         {
     70             visr[v] = 1;
     71             if (llink[v] == -1 || find(llink[v]))
     72             {
     73                 llink[v] = u;
     74                 rlink[u] = v;
     75                 return 1;
     76             }
     77         }
     78     }
     79     return 0;
     80 }
     81 int maxMacth()
     82 {
     83     int res = 0;
     84     for (int i = 1; i <= n; i++)
     85     {
     86         memset(visr, 0, sizeof(int) * (m + 1));
     87         res += find(i);
     88     }
     89     return res;
     90 }
     91 int main(int argc, char const *argv[])
     92 {
     93     ios::sync_with_stdio(false);
     94     cin.tie(0);
     95     cout.tie(0);
     96 #ifndef ONLINE_JUDGE
     97     freopen("in.txt", "r", stdin);
     98     freopen("out.txt", "w", stdout);
     99 #endif
    100     while (cin >> n >> m >> k && (m + n + k))
    101     {
    102         init();
    103         for (int i = 0; i < k; i++)
    104         {
    105             int x, y;
    106             cin >> x >> y;
    107             add(x, y);
    108         }
    109         int ans = maxMacth();
    110         memset(visl, 0, sizeof visl);
    111         memset(visr, 0, sizeof visr);
    112         for (int i = 1; i <= n; i++) //再次匹配,找到哪些点需要匹配
    113             if (rlink[i] == -1)
    114                 find(i);
    115         cout << ans << " ";
    116         for (int i = 1; i <= n; i++)
    117             if (!visl[i])
    118                 cout << "r" << i << " ";
    119         for (int i = 1; i <= m; i++)
    120             if (visr[i])
    121                 cout << "c" << i << ' ';
    122         cout << "
    ";
    123     }
    124     return 0;
    125 }
    View Code
  • 相关阅读:
    Matlab曲面拟合和插值
    插值(scipy.interpolate)
    坐标系旋转后的点坐标、坐标点旋转后的点坐标
    halcon相机标定及图像矫正
    别再问我们用什么画图的了!问就是excalidraw
    Windows下如何玩转火热的go-zero
    我用go-zero开发了第一个线上项目
    Java基础差,需要怎么补
    2019-给你六个建议
    简说Java线程的那几个启动方式
  • 原文地址:https://www.cnblogs.com/mooleetzi/p/11317779.html
Copyright © 2011-2022 走看看