zoukankan      html  css  js  c++  java
  • 2013 Multi-University Training Contest 9

    HDU-4687 Boke and Tsukkomi

    题意:给定一个简单图,询问哪些边如果选择的话会使得最大的连边数减少。

    解法:套用一般图的最大匹配算法(带花树)先算出最大匹配数,然后枚举一条边被选择(注意:如果改变被选择,则两端点相邻的边都应删除),看是否只减少一条匹配边。

    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    const int MAXN = 45;
    int n, m;
    int u[150], v[150];
    
    struct Graph {
    
        bool mat[MAXN + 1][MAXN + 1];
        int n;
    
        bool inque[MAXN + 1];
        int que[MAXN], head, tail;
    
        int match[MAXN + 1], father[MAXN + 1], base[MAXN + 1];
        
        int inpath[MAXN + 1];
        static int pcnt;               // count of paths have existed
    
        int inblossom[MAXN + 1];
        static int bcnt;               // count of blossoms have existed
    
        void init(int _n) {
            n = _n;
            for (int i = 1; i <= n; ++i) {
                match[i] = 0;
                for (int j = 1; j <= n; ++j)
                    mat[i][j] = false;
            }
        }
    
        int pop() { return que[head++]; }
    
        void push(int x) {
            que[tail++] = x;
            inque[x] = true;
        }
    
        void add_edge(int a, int b) {
            mat[a][b] = mat[b][a] = true;
        }
    
    
        int find_ancestor(int u, int v) {
            ++pcnt;
            while (u) {
                u = base[u];
                inpath[u] = pcnt;
                u = father[match[u]];
               // if match[u] == 0, meaning u is the root node, it also works, because father[0] == 0
            }
            while (true) {
                v = base[v];
                if (inpath[v] == pcnt) return v;
                v = father[match[v]];
            }
        }
    
        void reset(int u, int anc) {
            while (u != anc) {
                int v = match[u];
                inblossom[base[v]] = bcnt;
                inblossom[base[u]] = bcnt;
                v = father[v];
                if (base[v] != anc) father[v] = match[u];
                u = v;
            }
        }
    
        void contract(int u, int v) {
            int anc = find_ancestor(u, v);
            ++bcnt;
            reset(u, anc);
            reset(v, anc);
            if (base[u] != anc) father[u] = v;
            if (base[v] != anc) father[v] = u;
            for (int i = 1; i <= n; ++i)
                if (inblossom[base[i]] == bcnt) {
                    base[i] = anc;
                    if (!inque[i]) push(i);
                }
        }
    
        int find_augment(int start) {
            for (int i = 1; i <= n; ++i) {
                father[i] = 0;
                inque[i] = false;
                base[i] = i;
            }
            head = 0; tail = 0; push(start);
            while (head < tail) {
                int u = pop();
                for (int v = 1; v <= n; ++v)
                    if (mat[u][v] && base[v] != base[u] && match[v] != u) {
                        if (v == start || (match[v] && father[match[v]]))
                                                       // node v is out-point
                            contract(u, v);               // make blossom
                        else {
                            if (father[v] == 0) {       // not in-point
                                if (match[v]) {           // has matched
                                    push(match[v]);       // match[v] becomes out-point
                                    father[v] = u;       // v becomes in-point
                                } else {
                                    father[v] = u;       // node v is another end
                                    return v;
                                }
                            }
                        }
                    }
            }
            return 0;
        }
    
        void augment(int finish) {
            int u = finish, v, w;
            while (u) {
                v = father[u];
                w = match[v];
                match[u] = v;
                match[v] = u;
                u = w;
            }
        }
    
        int graph_max_match() {
            int ans = 0;
            for (int i = 1; i <= n; ++i)
                if (match[i] == 0) {
                    int finish = find_augment(i);
                    if (finish) {
                        augment(finish);
                        ans += 2;
                    }
                }
            return ans;
        }
    
    } g;
    
    int Graph::bcnt = 0, Graph::pcnt = 0;
    vector<int>vt;
    
    int main() {
        while (scanf("%d %d", &n, &m) != EOF) {
            g.init(n);
            vt.clear();
            bool first = true;
            for (int i = 0; i < m; ++i) {
                scanf("%d %d", &u[i], &v[i]);
                g.add_edge(u[i], v[i]);
            }
            int MaxPair = g.graph_max_match() / 2; // 返回的是匹配的点数 
            for (int i = 0; i < m; ++i) {
                g.init(n);
                int a = u[i], b = v[i];
                for (int j = 0; j < m; ++j) { // 如果匹配这条边那么两个端点其他连边都是不能匹配的 
                    if (u[j] == a || u[j] == b || v[j] == a || v[j] == b) continue;
                    g.add_edge(u[j], v[j]);
                }
                int tmp = g.graph_max_match() / 2;
                if (tmp != MaxPair - 1) vt.push_back(i+1);
            }
            printf("%d
    ", vt.size());
            for (int i = 0; i < (int)vt.size(); ++i) {
                printf(i == 0 ? "%d" : " %d", vt[i]);
            }
            puts("");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    COCO2018 目标检测
    最小生成树[摘录自严长生老师的网站]
    PANet训练自己的数据(VIA标注)
    图的遍历[摘录自严长生老师的网站]
    图的链式存储(邻接表)【摘录自严长生老师的网站】
    Android写入到mysql里的中文总是乱码?
    Mac 当xampp里mysql无法启动的解决办法
    【代码段】Android Studio使用DatePicker选择日期
    Android jdbc连接mysql报错解决方案 (Communications link failure)
    绝命毒师口语精析(4)
  • 原文地址:https://www.cnblogs.com/Lyush/p/3271491.html
Copyright © 2011-2022 走看看