zoukankan      html  css  js  c++  java
  • Uva 11419 我是SAM

    题目链接:https://vjudge.net/problem/UVA-11419

    题意:一个网格里面有一些目标,可以从某一行,某一列发射一发子弹,可以打穿;

    求最少的子弹,和在哪里打?

    分析:

    听说可以用吗MCMF做,没多想;

    一个目标,拆成两个点,X,Y,X与Y之间连一条边,现在,在这些点里面选出一些点,使得每一条边都有一个端点被覆盖,这就是最小点覆盖=最大匹配(证明在之前写过,博客里可以找到,证明很有意思);

    然后还要找出哪些被覆盖了;

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <vector>
      4 #include <algorithm>
      5 using namespace std;
      6 
      7 const int maxn = 1000 + 5; // 单侧顶点的最大数目
      8 
      9 // 二分图最大基数匹配
     10 struct BPM
     11 {
     12     int n, m;               // 左右顶点个数
     13     vector<int> G[maxn];    // 邻接表
     14     int left[maxn];         // left[i]为右边第i个点的匹配点编号,-1表示不存在
     15     bool T[maxn];           // T[i]为右边第i个点是否已标记
     16 
     17     int right[maxn];        // 求最小覆盖用
     18     bool S[maxn];           // 求最小覆盖用
     19 
     20     void init(int n, int m)
     21     {
     22         this->n = n;
     23         this->m = m;
     24         for(int i = 0; i < n; i++) G[i].clear();
     25     }
     26 
     27     void AddEdge(int u, int v)
     28     {
     29         G[u].push_back(v);
     30     }
     31 
     32     bool match(int u)
     33     {
     34         S[u] = true;
     35         for(int i = 0; i < G[u].size(); i++)
     36         {
     37             int v = G[u][i];
     38             if (!T[v])
     39             {
     40                 T[v] = true;
     41                 if (left[v] == -1 || match(left[v]))
     42                 {
     43                     left[v] = u;
     44                     right[u] = v;
     45                     return true;
     46                 }
     47             }
     48         }
     49         return false;
     50     }
     51 
     52     // 求最大匹配
     53     int solve()
     54     {
     55         memset(left, -1, sizeof(left));
     56         memset(right, -1, sizeof(right));
     57         int ans = 0;
     58         for(int u = 0; u < n; u++)   // 从左边结点u开始增广
     59         {
     60             memset(S, 0, sizeof(S));
     61             memset(T, 0, sizeof(T));
     62             if(match(u)) ans++;
     63         }
     64         return ans;
     65     }
     66 
     67     // 求最小覆盖。X和Y为最小覆盖中的点集
     68     int mincover(vector<int>& X, vector<int>& Y)
     69     {
     70         int ans = solve();
     71         memset(S, 0, sizeof(S));
     72         memset(T, 0, sizeof(T));
     73         for(int u = 0; u < n; u++)
     74             if(right[u] == -1) match(u); // 从所有X未盖点出发增广
     75         for(int u = 0; u < n; u++)
     76             if(!S[u]) X.push_back(u); // X中的未标记点
     77         for(int v = 0; v < m; v++)
     78             if(T[v]) Y.push_back(v);  // Y中的已标记点
     79         return ans;
     80     }
     81 };
     82 
     83 BPM solver;
     84 
     85 int R, C, N;
     86 
     87 int main()
     88 {
     89     int kase = 0;
     90     while(scanf("%d%d%d", &R, &C, &N) == 3 && R && C && N)
     91     {
     92         solver.init(R, C);
     93         for(int i = 0; i < N; i++)
     94         {
     95             int r, c;
     96             scanf("%d%d", &r, &c);
     97             r--;
     98             c--;
     99             solver.AddEdge(r, c);
    100         }
    101         vector<int> X, Y;
    102         int ans = solver.mincover(X, Y);
    103         printf("%d", ans);
    104         for(int i = 0; i < X.size(); i++) printf(" r%d", X[i]+1);
    105         for(int i = 0; i < Y.size(); i++) printf(" c%d", Y[i]+1);
    106         printf("
    ");
    107     }
    108     return 0;
    109 }
    View Code
  • 相关阅读:
    题解-CF468E Permanent
    CSP2021 游记
    二项式系数相关
    欧拉反演
    欧拉函数
    [快速幂]1
    GMT绘制地形起伏
    华为mate8双击唤醒屏幕
    回家乡了
    CSP-S2021
  • 原文地址:https://www.cnblogs.com/TreeDream/p/6798472.html
Copyright © 2011-2022 走看看