UVa 11419 SAM I AM (最小点覆盖,匈牙利算法)

来源:互联网 发布:哈利波特英文原版淘宝 编辑:程序博客网 时间:2024/05/20 05:24

题目:https://vjudge.net/contest/136139#problem/E
题意:

有一个矩阵中放置的一写东西,然后你有一门炮,每次能横向或纵向开一炮,是这一行所有的东西摧毁。问你最少花多少炮弹摧毁所有的东西?输出一组解

分析:

这题是求最小覆盖数,以前做过不出输出方案的
最小覆盖数=最大匹配数
求最大匹配数用匈牙利算法即可
输出最小覆盖集:
从未匹配点找增广路,划分S和T集合
那么在S’和T中的就是最小覆盖集
可以这么理解S’中的是未匹配的,每个未匹配的都需要安排一个发射点
T中的是和S中匹配的,安排一个发射点就能都把匹配的都打掉了

代码:

// UVa11419 SAM I AM// Rujia Liu#include <cstdio>#include <cstring>#include <vector>#include <algorithm>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() {    int kase = 0;    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;}
0 0
原创粉丝点击