zoukankan      html  css  js  c++  java
  • ZOJ 2676 Network Wars ★(最小割算法介绍 && 01分数规划)

    题意】给出一个带权无向图,求割集,且割集的平均边权最小。 【分析】 先尝试着用更一般的形式重新叙述本问题。设向量w表示边的权值,令向量c=(1, 1, 1, ……, 1)表示选边的代价,于是原问题等价为: Minimize   λ = f(x) = sigma(wexe)/sigma(1*xe) = wx / cx 其中, x表示一个解向量,xe∈{0, 1} ,即对于每条边都有选与不选两种决策,并且选出的边集组成一个s-t边割集。 联系已有的知识,这是一个0-1分数规划。在胡伯涛《最小割模型在信息学竞赛中的应用》中已经给出了这类规划的普遍转化方法:构造一个新函数g(λ) = min {(wc)•x} 即对每条边∨e ∈ E ,进行重赋权:we' = we - ce•λ = we - λ。g(λ)便是在这个重新赋权的图上,求一个最小容量的s-t边割集。注意一些细节:若we' < 0,又由于目标函数是加和取最小的操作,则该边必然是在边割集内。对于剩下的所有we' > 0的边,直接利用最小割模型求出s-t割即可。 于是主算法便是对最优解*λ的二分查找,每次查找用最小割模型来判定,进而缩小查找范围,直到满足精度要求。 【最小割算法:割点集、割边集】 通常我们说的最小割都是最小边割,对应求的也就是最小边割集。如果要求最小点割集,则拆点转换为边割:(每个点i拆成i和i',连一条(i, i', 1)的边,原图中的边(u,v)转化为(u', v, oo),求源点s+n到汇点t的最大流)就行了。 由于最大流最小割定理中,即最大流的流值等于最小割容量。所以在问题的实现上分两步:(Δ)先求得最大流,再在得到最大流f后的残留网络Gf中,从s开始深度优先遍历(DFS),所有被遍历到的点,即构成点集S。其余的点即构成点集T(不需要再从T遍历,挺麻烦)。这样割点集便求出来了。 注意,虽然最小割[S,T]中的边都是满流边,但满流边不一定都是最小割中的边。在某些特殊图中,很人容易认为不用DFS,就可以直接得出割。下面举一个二分图的例子。 求最小割的二分图例子   图1.2(a) 给出了一个基于二分图构造的流网络。由于从X部到Y部都是容量均为正无限的边,都不可能是最小割中的边,有人便会错误地认为与源或汇关联的满流边便组成了最小割(图1.2(a)的红色边)。然而实际上,在该网络的残留网络中,结点2与3应该与源s是连通的(图1.2(b)的蓝色路径),所以最小割应该是图1.2(b)中的红色边。 所以割边集的求法应该是:先求出割点集,然后枚举满流边,如果边的两个端点分别在S集和T集中,则该边是割边。   【代码】  
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #define MID(x,y) ((x+y)/2)
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    const int MAXV = 105;
    const int MAXE = 1005;
    const int oo = 0x3fffffff;
    const double eps = 1e-2;
    bool dy(double x,double y)  {   return x > y + eps;} 		// x > y
    bool xy(double x,double y)  {   return x < y - eps;} 		// x < y
    bool dyd(double x,double y) {   return x > y - eps;} 		// x >= y
    bool xyd(double x,double y) {   return x < y + eps;}     	// x <= y
    bool dd(double x,double y)  {   return fabs( x - y ) < eps;}    // x == y
    
    template 
    struct Dinic{
        struct node{
            int u, v;
            T flow;
            int opp;
            int next;
        }arc[2*MAXE];
        int vn, en, head[MAXV];
        int cur[MAXV];
        int q[MAXV];
        int path[2*MAXE], top;
        int dep[MAXV];
        void init(int n){
            vn = n;
            en = 0;
            mem(head, -1);
        }
        void insert_flow(int u, int v, T flow){
            arc[en].u = u;
            arc[en].v = v;
            arc[en].flow = flow;
            arc[en].next = head[u];
            head[u] = en ++;
    
            arc[en].u = v;
            arc[en].v = u;
            arc[en].flow = 0;
            arc[en].next = head[v];
            head[v] = en ++;
        }
        bool bfs(int s, int t){
            mem(dep, -1);
            int lq = 0, rq = 1;
            dep[s] = 0;
            q[lq] = s;
            while(lq < rq){
                int u = q[lq ++];
                if (u == t){
                    return true;
                }
                for (int i = head[u]; i != -1; i = arc[i].next){
                    int v = arc[i].v;
                    if (dep[v] == -1 && arc[i].flow > 0){
                        dep[v] = dep[u] + 1;
                        q[rq ++] = v;
                    }
                }
            }
            return false;
        }
        T solve(int s, int t){
            T maxflow = 0;
            while(bfs(s, t)){
                int i, j;
                for (i = 1; i <= vn; i ++)  cur[i] = head[i];
                for (i = s, top = 0;;){
                    if (i == t){
                        int mink;
                        T minflow = 0x3fffffff;
                        for (int k = 0; k < top; k ++)
                            if (minflow > arc[path[k]].flow){
                                minflow = arc[path[k]].flow;
                                mink = k;
                            }
                        for (int k = 0; k < top; k ++)
                            arc[path[k]].flow -= minflow, arc[path[k]^1].flow += minflow;
                        maxflow += minflow;
                        top = mink;
                        i = arc[path[top]].u;
                    }
                    for (j = cur[i]; j != -1; cur[i] = j = arc[j].next){
                        int v = arc[j].v;
                        if (arc[j].flow && dep[v] == dep[i] + 1)
                            break;
                    }
                    if (j != -1){
                        path[top ++] = j;
                        i = arc[j].v;
                    }
                    else{
                        if (top == 0)   break;
                        dep[i] = -1;
                        i = arc[path[-- top]].u;
                    }
                }
            }
            return maxflow;
        }
    };
    Dinic  dinic;
    
    int n, m;
    struct path{
        int u, v;
        double cost;
    }p[MAXE];
    int st[MAXV];
    bool vis[MAXV];
    void dfs(int u, int p){
        st[u] = p;
        vis[u] = 1;
        for (int i = dinic.head[u]; i != -1; i = dinic.arc[i].next){
            if (dinic.arc[i].flow <= 0) continue;
            int v = dinic.arc[i].v;
            if (!vis[v]){
                dfs(v, p);
            }
        }
        return ;
    }
    double min_cut(double r){
        double res = 0.0;
        dinic.init(n);
        for (int i = 0; i < m; i ++){
            if (p[i].cost - r < 0){
                res += p[i].cost - r;
            }
            else{
                dinic.insert_flow(p[i].u, p[i].v, p[i].cost - r);
                dinic.insert_flow(p[i].v, p[i].u, p[i].cost - r);
            }
        }
        res += dinic.solve(1, n);
        return res;
    }
    int main(){
    	//freopen("test.in", "r", stdin);
    	//freopen("test.out", "w", stdout);
        int ca = 1;
        while(scanf("%d %d", &n, &m) != EOF){
            if (ca > 1)
                printf("
    ");
            double max_cost = 0.0;
            for (int i = 0; i < m; i ++){
                scanf("%d %d %lf", &p[i].u, &p[i].v, &p[i].cost);
                max_cost = max(max_cost, p[i].cost);
            }
            double l = 0, r = max_cost;
            while(xy(l, r)){
                double mid = MID(l, r);
                double cut = min_cut(mid);
                if (xy(cut, 0)){
                    r = mid;
                }
                else{
                    l = mid;
                }
            }
            mem(st, 0);
            mem(vis, 0);
            dfs(1, 1);
            int counts = 0;
            vector  cuts;
            cuts.clear();
            for (int i = 0; i < m; i ++){
                if (p[i].cost - r < 0 || st[p[i].u] != st[p[i].v]){
                    cuts.push_back(i+1);
                    counts ++;
                }
            }
            printf("%d
    ", counts);
            for (int i = 0; i < counts; i ++){
                if (i == 0) printf("%d", cuts[i]);
                else    printf(" %d", cuts[i]);
            }
            printf("
    ");
            ca ++;
        }
    	return 0;
    }
    
  • 相关阅读:
    Oracle中有大量的sniped会话
    Error 1130: Host '127.0.0.1' is not allowed to connect to this MySQL server
    汉字转换为拼音以及缩写(javascript)
    高效率随机删除数据(不重复)
    vs2010 舒服背景 优雅字体 配置
    mvc中的ViewData用到webfrom中去
    jquery ajax return值 没有返回 的解决方法
    zShowBox (图片放大展示jquery版 兼容性好)
    动感效果的TAB选项卡 jquery 插件
    loading 加载提示······
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/4114267.html
Copyright © 2011-2022 走看看