zoukankan      html  css  js  c++  java
  • HDU 6214 Smallest Minimum Cut 最小割,权值编码

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6214

    题意:求边数最小的割。

    解法:

    建边的时候每条边权 w = w * (E + 1) + 1;
    这样得到最大流 maxflow / (E + 1) ,最少割边数 maxflow % (E + 1)

    道理很简单,如果原先两类割边都是最小割,那么求出的最大流相等
    但边权变换后只有边数小的才是最小割了

     乘(E+1)是为了保证边数叠加后依然是余数,不至于影响求最小割的结果

    因为假设最小割=k,那么现在新图的最小割为k*(E+1)+p,p为割的边数,本质上是,原来你割一条边,需要代价,

    由于你要求边数最小 所以你多割一条边,就多一的代价,但是这个代价不足以影响到原来的代价。
    原来割一条边,代价xi,现在割一条边,代价xi*A+1,只要让A>m+1,m为边数,即使割了所有的边,自己加上去的代价也就m
     
    在QQ群里还看到一种解法,就是跑2次Dinic,这个显然是不对的吧。。最小割一定是满流,但是漫流的不一定是最小割吧。。。
     
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 410;
    const int maxm = 50010;
    const int inf = 0x3f3f3f3f;
    struct G
    {
        int v, cap, next;
        G() {}
        G(int v, int cap, int next) : v(v), cap(cap), next(next) {}
    } E[maxm];
    int p[maxn], T;
    int d[maxn], temp_p[maxn], qw[maxn]; //d顶点到源点的距离标号,temp_p当前狐优化,qw队列
    void init()
    {
        memset(p, -1, sizeof(p));
        T = 0;
    }
    void add(int u, int v, int cap)
    {
        E[T] = G(v, cap, p[u]);
        p[u] = T++;
        E[T] = G(u, 0, p[v]);
        p[v] = T++;
    }
    bool bfs(int st, int en, int n)
    {
        int i, u, v, head, tail;
        for(i = 0; i <= n; i++) d[i] = -1;
        head = tail = 0;
        d[st] = 0;
        qw[tail] = st;
        while(head <= tail)
        {
            u = qw[head++];
            for(i = p[u]; i + 1; i = E[i].next)
            {
                v = E[i].v;
                if(d[v] == -1 && E[i].cap > 0)
                {
                    d[v] = d[u] + 1;
                    qw[++tail] = v;
                }
            }
        }
        return (d[en] != -1);
    }
    int dfs(int u, int en, int f)
    {
        if(u == en || f == 0) return f;
        int flow = 0, temp;
        for(; temp_p[u] + 1; temp_p[u] = E[temp_p[u]].next)
        {
            G& e = E[temp_p[u]];
            if(d[u] + 1 == d[e.v])
            {
                temp = dfs(e.v, en, min(f, e.cap));
                if(temp > 0)
                {
                    e.cap -= temp;
                    E[temp_p[u] ^ 1].cap += temp;
                    flow += temp;
                    f -= temp;
                    if(f == 0)  break;
                }
            }
        }
        return flow;
    }
    int dinic(int st, int en, int n)
    {
        int i, ans = 0;
        while(bfs(st, en, n))
        {
            for(i = 0; i <= n; i++) temp_p[i] = p[i];
            ans += dfs(st, en, inf);
        }
        return ans;
    }
    
    int main()
    {
        int T, n, m;
        scanf("%d", &T);
        while(T--)
        {
            scanf("%d %d", &n,&m);
            init();
            int s, t;
            scanf("%d %d", &s, &t);
            for(int i=1; i<=m; i++){
                int u, v, w;
                scanf("%d %d %d", &u,&v,&w);
                add(u, v, w*(m+1)+1);
            }
            int ans = dinic(s, t, n+1);
            printf("%d
    ", ans%(m+1));
        }
        return 0;
    }
    
  • 相关阅读:
    Windows下如何检测用户修改了系统时间并且把系统时间改回来
    洛谷 1220 关路灯
    洛谷 2279 [HNOI2003]消防局的设立
    洛谷 1498 南蛮图腾
    bzoj 1036 [ZJOI2008]树的统计Count 树链剖分模板
    codevs 1021 玛丽卡 SPFA
    codevs 1077 多源最短路 flyod
    Vijos P1133 装箱问题 01背包
    codevs 1069 关押罪犯 并查集
    codevs 1073 家族 并查集
  • 原文地址:https://www.cnblogs.com/spfa/p/7544811.html
Copyright © 2011-2022 走看看