1. 程式人生 > >SAM I AM UVA - 11419 (二分圖最小覆蓋)

SAM I AM UVA - 11419 (二分圖最小覆蓋)

傳送門

題意:給定一個矩形,在這個矩形上有若干個東西,然後可以在每行或者每列放置一個大炮,可以把這一行或者這一列消完,現在要使用最少的大炮,問安置多少個,並且輸出位置。

題解:首先對於每個位置,要麼是放置在行的大炮消滅他要麼是列的大炮消滅他,然後根據所在的行列建兩個結點,一個行結點,一個列結點,連起來,對於剩下的位置依舊如此,然後行在左邊,列在右邊,那麼跑一個二分圖的最小點覆蓋即可。

附上程式碼:


#include<bits/stdc++.h>

using namespace std;

const int maxn = 1000 + 5; // 單側頂點的最大數目

// 二分圖最大基數匹配
struct BPM {
  int n, m;               // 左右頂點個數
  vector<int> G[maxn];    // 鄰接表
  int left[maxn];         // left[i]為右邊第i個點的匹配點編號,-1表示不存在
  bool T[maxn];           // T[i]為右邊第i個點是否已標記

  int right[maxn];        // 求最小覆蓋用
  bool S[maxn];           // 求最小覆蓋用

  void init(int n, int m) {
    this->n = n;
    this->m = m;
    for(int i = 0; i < n; i++) G[i].clear();
  }

  void AddEdge(int u, int v) {
    G[u].push_back(v);
  }

  bool match(int u){
    S[u] = true;
    for(int i = 0; i < G[u].size(); i++) {
      int v = G[u][i];
      if (!T[v]){
        T[v] = true;
        if (left[v] == -1 || match(left[v])){
          left[v] = u;
          right[u] = v;
          return true;
        }
      }
    }
    return false;
  }

  // 求最大匹配
  int solve() {
    memset(left, -1, sizeof(left));
    memset(right, -1, sizeof(right));
    int ans = 0;
    for(int u = 0; u < n; u++) { // 從左邊結點u開始增廣
      memset(S, 0, sizeof(S));
      memset(T, 0, sizeof(T));
      if(match(u)) ans++;
    }
    return ans;
  }

  // 求最小覆蓋。X和Y為最小覆蓋中的點集
  int mincover(vector<int>& X, vector<int>& Y) {
    int ans = solve();
    memset(S, 0, sizeof(S));
    memset(T, 0, sizeof(T));
    for(int u = 0; u < n; u++)
      if(right[u] == -1) match(u); // 從所有X未蓋點出發增廣
    for(int u = 0; u < n; u++)
      if(!S[u]) X.push_back(u); // X中的未標記點
    for(int v = 0; v < m; v++)
      if(T[v]) Y.push_back(v);  // Y中的已標記點
   return ans;
  }
};

BPM solver;

int R,C,N;

int main()
{
    while(scanf("%d%d%d",&R,&C,&N)==3&&R&&C&&N){
        solver.init(R,C);
        for(int i=0;i<N;i++){
            int r,c;
            scanf("%d%d",&r,&c);
            r--;c--;
            solver.AddEdge(r,c);
        }
        vector<int>X,Y;
        int ans=solver.mincover(X,Y);
        printf("%d",ans);
        for(int i=0;i<X.size();i++){
            printf(" r%d",X[i]+1);
        }
        for(int i=0;i<Y.size();i++){
            printf(" c%d",Y[i]+1);
        }
        printf("\n");
    }
    return 0;
}