2013 Multi-University Training Contest 9

HDU-4687 Boke and Tsukkomi

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

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

2013 Multi-University Training Contest 9
#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\n", vt.size());

        for (int i = 0; i < (int)vt.size(); ++i) {

            printf(i == 0 ? "%d" : " %d", vt[i]);

        }

        puts("");

    }

    return 0;

}
View Code

 

 

你可能感兴趣的:(test)