zoukankan      html  css  js  c++  java
  • HDU 6081 度度熊的王国战略(全局最小割Stoer-Wagner算法)

    Problem Description

    度度熊国王率领着喵哈哈族的勇士,准备进攻哗啦啦族。
    哗啦啦族是一个强悍的民族,里面有充满智慧的谋士,拥有无穷力量的战士。
    所以这一场战争,将会十分艰难。
    为了更好的进攻哗啦啦族,度度熊决定首先应该从内部瓦解哗啦啦族。
    第一步就是应该使得哗啦啦族内部不能同心齐力,需要内部有间隙。
    哗啦啦族一共有n个将领,他们一共有m个强关系,摧毁每一个强关系都需要一定的代价。
    现在度度熊命令你需要摧毁一些强关系,使得内部的将领,不能通过这些强关系,连成一个完整的连通块,以保证战争的顺利进行。
    请问最少应该付出多少的代价。

    Input

    本题包含若干组测试数据。
    第一行两个整数n,m,表示有n个将领,m个关系。
    接下来m行,每行三个整数u,v,w。表示u将领和v将领之间存在一个强关系,摧毁这个强关系需要代价w

    数据范围:

    2<=n<=3000
    1<=m<=100000
    1<=u,v<=n
    1<=w<=1000


    题目大意:求全局最小割。
    题解:就是一标准的Stoer-Wagner算法模板题,邻接表法理论复杂度(O(nm log(m)))。见:全局最小割StoerWagner算法详解
    PS:网上绝大部分题解是错误的,反例很容易能找出。但是却能AC,可以看出此次百度之星的出题人非常不认真啊。

    代码(6770MS):

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <numeric>
    
    typedef long long LL;
    
    const int MAXV = 3010;
    const int MAXE = 100010 * 2;
    const int INF = 0x3f3f3f3f;
    
    int head[MAXV], val[MAXV], ecnt;
    int to[MAXE], next[MAXE], weight[MAXE];
    bool vis[MAXV];
    int fa[MAXV], link[MAXV];
    int n, m;
    
    void init() {
        memset(head + 1, -1, sizeof(int) * n);
        memset(link + 1, -1, sizeof(int) * n);
        for (int i = 1; i <= n; ++i)
            fa[i] = i;
        ecnt = 0;
    }
    
    void add_edge(int u, int v, int w) {
        to[ecnt] = v; weight[ecnt] = w; next[ecnt] = head[u]; head[u] = ecnt++;
        to[ecnt] = u; weight[ecnt] = w; next[ecnt] = head[v]; head[v] = ecnt++;
    }
    
    int findset(int u) { // 并查集
        return u == fa[u] ? u : fa[u] = findset(fa[u]);
    }
    
    void merge(int u, int v) {
        int p = u;
        while (~link[p]) p = link[p];
        link[p] = v;
        fa[v] = u;
    }
    
    int MinimumCutPhase(int cnt, int &s, int &t) {
        memset(val + 1, 0, sizeof(int) * n);
        memset(vis + 1, 0, sizeof(bool) * n);
        std::priority_queue<std::pair<int, int>> que;
        t = 1;
        while (--cnt) {
            vis[s = t] = true;
            for (int u = s; ~u; u = link[u]) {
                for (int p = head[u]; ~p; p = next[p]) {
                    int v = findset(to[p]);
                    if (!vis[v])
                        que.push(std::make_pair(val[v] += weight[p], v));
                }
            }
            t = 0;
            while (!t) {
                if (que.empty()) return 0; // 图不连通
                auto pa = que.top(); que.pop();
                if (val[pa.second] == pa.first)
                    t = pa.second;
            }
        }
        return val[t];
    }
    
    int StoerWagner() {
        int res = INF;
        for (int i = n, s, t; i > 1; --i) {
            res = std::min(res, MinimumCutPhase(i, s, t));
            if (res == 0)
                break;
            merge(s, t);
        }
        return res;
    }
    
    int main() {
        while (scanf("%d%d", &n, &m) != EOF) {
            init();
            for (int i = 0, u, v, w; i < m; ++i) {
                scanf("%d%d%d", &u, &v, &w);
                add_edge(u, v, w);
            }
            printf("%d
    ", StoerWagner());
        }
    }
    

    顺便试一下pb_ds库,详见IOI集训队论文《C++的pb_ds库在OI中的应用——于纪平》
    pb_ds优先队列学习笔记

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <numeric>
    #include <ext/pb_ds/priority_queue.hpp>
    
    typedef long long LL;
    
    /// 都只试了一次,不一定准确
    //typedef __gnu_pbds::priority_queue<std::pair<int, int>, std::less<std::pair<int, int>>, __gnu_pbds::binary_heap_tag> PQue; // TLE
    //typedef __gnu_pbds::priority_queue<std::pair<int, int>, std::less<std::pair<int, int>>, __gnu_pbds::binomial_heap_tag> PQue; // 7940MS
    //typedef __gnu_pbds::priority_queue<std::pair<int, int>, std::less<std::pair<int, int>>, __gnu_pbds::rc_binomial_heap_tag> PQue; // 9204MS
    //typedef __gnu_pbds::priority_queue<std::pair<int, int>, std::less<std::pair<int, int>>, __gnu_pbds::pairing_heap_tag> PQue; // 6770MS
    typedef __gnu_pbds::priority_queue<std::pair<int, int>, std::less<std::pair<int, int>>, __gnu_pbds::thin_heap_tag> PQue; // 8954MS
    
    const int MAXV = 3010;
    const int MAXE = 100010 * 2;
    const int INF = 0x3f3f3f3f;
    
    int head[MAXV], val[MAXV], ecnt;
    int to[MAXE], next[MAXE], weight[MAXE];
    bool vis[MAXV];
    int fa[MAXV], link[MAXV];
    PQue::point_iterator iter[MAXV];
    int n, m;
    
    void init() {
        memset(head + 1, -1, sizeof(int) * n);
        memset(link + 1, -1, sizeof(int) * n);
        for (int i = 1; i <= n; ++i)
            fa[i] = i;
        ecnt = 0;
    }
    
    void add_edge(int u, int v, int w) {
        to[ecnt] = v; weight[ecnt] = w; next[ecnt] = head[u]; head[u] = ecnt++;
        to[ecnt] = u; weight[ecnt] = w; next[ecnt] = head[v]; head[v] = ecnt++;
    }
    
    int findset(int u) { // 并查集
        return u == fa[u] ? u : fa[u] = findset(fa[u]);
    }
    
    void merge(int u, int v) { // 合并
        int p = u;
        while (~link[p]) p = link[p];
        link[p] = v;
        fa[v] = u;
    }
    
    int MinimumCutPhase(int cnt, int &s, int &t) {
        memset(val + 1, 0, sizeof(int) * n);
        memset(vis + 1, 0, sizeof(bool) * n);
        PQue que;
        for (int i = 1; i <= n; ++i)
            iter[i] = 0;
        t = 1;
        while (--cnt) {
            vis[s = t] = true;
            for (int u = s; ~u; u = link[u]) {
                for (int p = head[u]; ~p; p = next[p]) {
                    int v = findset(to[p]);
                    if (!vis[v]) {
                        if (iter[v] != 0)
                            que.modify(iter[v], std::make_pair(val[v] += weight[p], v));
                        else
                            iter[v] = que.push(std::make_pair(val[v] += weight[p], v));
                    }
                }
            }
    
            if (que.empty()) return 0; // 图不连通
            t = que.top().second; que.pop();
        }
        return val[t];
    }
    
    int StoerWagner() {
        int res = INF;
        for (int i = n, s, t; i > 1; --i) {
            res = std::min(res, MinimumCutPhase(i, s, t));
            if (res == 0)
                break;
            merge(s, t);
        }
        return res;
    }
    
    int main() {
        while (scanf("%d%d", &n, &m) != EOF) {
            init();
            for (int i = 0, u, v, w; i < m; ++i) {
                scanf("%d%d%d", &u, &v, &w);
                add_edge(u, v, w);
            }
            printf("%d
    ", StoerWagner());
        }
    }
    
  • 相关阅读:
    动态加载js文件并且执行回调方法
    二分查找法查找数组元素下表
    用横线隔开字符串
    不要再拖别人的控件2.帮前面的东东加个事件
    IE6 外部样式引用不进来
    用jQuery+css+div 写一个 乱换效果
    不要再拖别人的控件3.为什么要学习.net控件开发
    带一键还原的FTP上传软件
    .net 四舍六入 五成双
    Fiddler实战之请求头(request headers)和响应头(response headers)
  • 原文地址:https://www.cnblogs.com/oyking/p/7340753.html
Copyright © 2011-2022 走看看