• 【HDU 4940】Destroy Transportation system(无源无汇带上下界可行流)


    Description

    Tom is a commander, his task is destroying his enemy’s transportation system.

    Let’s represent his enemy’s transportation system as a simple directed graph G with n nodes and m edges. Each node is a city and each directed edge is a directed road. Each edge from node u to node v is associated with two values D and B, D is the cost to destroy/remove such edge, B is the cost to build an undirected edge between u and v.

    His enemy can deliver supplies from city u to city v if and only if there is a directed path from u to v. At first they can deliver supplies from any city to any other cities. So the graph is a strongly-connected graph.

    He will choose a non-empty proper subset of cities, let’s denote this set as S. Let’s denote the complement set of S as T. He will command his soldiers to destroy all the edges (u, v) that u belongs to set S and v belongs to set T. 

    To destroy an edge, he must pay the related cost D. The total cost he will pay is X. You can use this formula to calculate X:

    After that, all the edges from S to T are destroyed. In order to deliver huge number of supplies from S to T, his enemy will change all the remained directed edges (u, v) that u belongs to set T and v belongs to set S into undirected edges. (Surely, those edges exist because the original graph is strongly-connected)

    To change an edge, they must remove the original directed edge at first, whose cost is D, then they have to build a new undirected edge, whose cost is B. The total cost they will pay is Y. You can use this formula to calculate Y:

    At last, if Y>=X, Tom will achieve his goal. But Tom is so lazy that he is unwilling to take a cup of time to choose a set S to make Y>=X, he hope to choose set S randomly! So he asks you if there is a set S, such that Y<X. If such set exists, he will feel unhappy, because he must choose set S carefully, otherwise he will become very happy.

    Input

    There are multiply test cases.

    The first line contains an integer T(T<=200), indicates the number of cases. 

    For each test case, the first line has two numbers n and m. 

    Next m lines describe each edge. Each line has four numbers u, v, D, B. 
    (2=<n<=200, 2=<m<=5000, 1=<u, v<=n, 0=<D, B<=100000)

    The meaning of all characters are described above. It is guaranteed that the input graph is strongly-connected.

    Output

    For each case, output "Case #X: " first, X is the case number starting from 1.If such set doesn’t exist, print “happy”, else print “unhappy”.

    Sample Input

    2
    3 3
    1 2 2 2
    2 3 2 2
    3 1 2 2
    3 3
    1 2 10 2
    2 3 2 2
    3 1 2 2

    Sample Output

    Case #1: happy
    Case #2: unhappy
    Hint
    In first sample, for any set S, X=2, Y=4. In second sample. S= {1}, T= {2, 3}, X=10, Y=4.

    Source

    2014 Multi-University Training Contest 7
     
    先来一个错误但是AC了(数据水)的算法:
    每个点单独作为S集合时,如果存在满足Y<X,就输出unhappy。否则输出happy。
     
    为什么错呢?输出happy时,即两个点单独作为S时,都有Y1>=X1,Y2>=X2,如果两个点之间没有边,它们一起作为S时,X=X1+X2,Y=Y1+Y2,则Y>=X;但是如果两个点有边相连,X=X1+X2-(S1到S2的D)-(S2到S1的D),Y=Y1+Y2-(S1到S2的D+B)-(S2到S1的D+B),那么Y+B12+B21>=X,就有可能是Y<X了。当输入

    1
    4 5
    1 4 10 2
    4 1 6 2
    2 1 1 1
    4 3 6 2
    3 2 4 2

    时,输出的是happy。可是实际上,选择1、4节点,Y=2,X=8,显然是unhappy。

    附上非正解代码:(AC了只能说明题目数据太水了)

    #include <cstdio>
    #include <cstring>
    #define N 205
    #define sf(x) scanf("%d",&x)
    int x[N],y[N];
    int main(){
        int t;
        sf(t);
        for(int cas=1;cas<=t;cas++){
            memset(x,0,sizeof x);
            memset(y,0,sizeof y);
            printf("Case #%d: ",cas);
            int n,m;
            sf(n);
            sf(m);
            for(int i=1;i<=m;i++){
                int u,v,d,b;
                sf(u);sf(v);sf(d);sf(b);
                x[u]+=d;
                y[v]+=d+b;
            }
            int ok=1;
            for(int i=1;i<=n;i++)
            if(x[i]>y[i])ok=0;
            if(ok)puts("happy");
            else puts("unhappy");
        }
    }

    正解是无源无汇带上下界判断是否有可行流。

    将问题转化为网络流问题:
    每条边下界为D,上界为D+B,如果存在可行流,那么
    $$sum_{substack{uin S \ vin overline {S}}} f_{uv} = sum_{substack{uin S \ vin overline {S}}}f_{uv}\D_{uv} leq f_{uv} leq D_{uv}+B_{uv}$$
    所以有
    $$sum_{substack{uin S \ vin overline {S}}} D_{uv} leq sum_{substack{uin S \ vin overline {S}}}D_{uv}+ B_{uv}$$
    因此只要求无源无汇上下界网络流是否存在可行流,如果不存在就是unhappy。
    而无源汇有上下界的网络流,是否有可行流可以这样求:
    人为加上源点s,汇点t,
    边权改为上界-下界(这样转化为下界为0),
    流入i点的下界和为in,流出的下界和为out,
    in>out则s 到 i 连边,流量为in-out;
    in<out则 i 到 t 连边,流量为out-in。

    求s到t的最大流,如果源点汇点连接的边全部满流则有可行解。

    参考国家集训队论文《一种简易的方法求解流量有上下界的网络中网络流问题》

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    #define N 500
    #define M 200001
    #define inf 0x3f3f3f3f
    struct edge{
        int to,next,cap,flow;
    }e[M];
    int head[N],cnt;
    int gap[N],dep[N],cur[N];
    void init(){
        cnt=0;
        memset(head, -1, sizeof head);
    }
    void add(int u,int v,int w,int rw=0){
        e[cnt]=(edge){v,head[u],w,0};
        head[u]=cnt++;
        e[cnt]=(edge){u,head[v],rw,0};
        head[v]=cnt++;
    }
    int q[N];
    void bfs(int st,int ed){
        memset(dep,-1,sizeof dep);
        memset(gap,0,sizeof gap);
        gap[0]=1;
        int front=0,rear=0;
        dep[ed]=0;
        q[rear++]=ed;
        while(front!=rear){
            int u=q[front++];
            for(int i=head[u];~i;i=e[i].next){
                int v=e[i].to;
                if(dep[v]!=-1)continue;
                q[rear++]=v;
                dep[v]=dep[u]+1;
                gap[dep[v]]++;
            }
        }
    }
    int s[N];
    int sap(int st,int ed,int n){
        bfs(st,ed);
        memcpy(cur,head,sizeof head);
        int top=0;
        int u=st;
        int ans=0;
        while(dep[st]<n){
            if(u==ed){
                int Min=inf;
                int inser;
                for(int i=0;i<top;i++)
                    if(Min>e[s[i]].cap-e[s[i]].flow){
                        Min=e[s[i]].cap-e[s[i]].flow;
                        inser=i;
                    }
                for(int i=0;i<top;i++){
                    e[s[i]].flow+=Min;
                    e[s[i]^1].flow-=Min;
                }
                ans+=Min;
                top=inser;
                u=e[s[top]^1].to;
                continue;
            }
            bool flag=false;
            int v;
            for(int i=cur[u];~i;i=e[i].next){
                v=e[i].to;
                if(e[i].cap-e[i].flow&&dep[v]+1==dep[u]){
                    flag=true;
                    cur[u]=i;
                    break;
                }
            }
            if(flag){
                s[top++]=cur[u];
                u=v;
                continue;
            }
            int Min=n;
            for(int i=head[u];~i;i=e[i].next)
                if(e[i].cap-e[i].flow &&dep[e[i].to]<Min){
                    Min=dep[e[i].to];
                    cur[u]=i;
                }
            gap[dep[u]]--;
            if(!gap[dep[u]])return ans;
            gap[dep[u]=Min+1]++;
            if(u!=st)u=e[s[--top]^1].to;
        }
        return ans;
    }
    int main(){
        int t;
        scanf("%d",&t);
        for(int cas=1;cas<=t;cas++){
            printf("Case #%d: ",cas);
            int n,m;
            scanf("%d%d",&n,&m);
            int in[N];
            int st=0,ed=n+1;
            memset(in,0,sizeof in);
            init();
            for(int i=1;i<=m;i++){
                int u,v,d,b;
                scanf("%d%d%d%d",&u,&v,&d,&b);
                add(u,v,b);
                in[v]+=d;
                in[u]-=d;
            }
            int need=0;
            for(int i=1;i<=n;i++){
                if(in[i]>0){
                    add(st,i,in[i]);
                    need+=in[i];
                }
                else add(i,ed,-in[i]);
            }
            int ans=sap(st, ed, ed+1);
            if(need==ans)puts("happy");
            else puts("unhappy");
        }
    }
  • 相关阅读:
    谈谈一些有趣的CSS题目(十二)-- 你该知道的字体 font-family
    谈谈一些有趣的CSS题目(十一)-- reset.css 知多少?
    【Web动画】SVG 实现复杂线条动画
    【Web动画】SVG 线条动画入门
    引人瞩目的 CSS 变量(CSS Variable)
    谈谈一些有趣的CSS题目(十)-- 结构性伪类选择器
    ROW_NUMBER() OVER函数的基本用法
    PL SQL笔记(三)
    pushState、replaceState、onpopstate 实现Ajax页面的前进后退刷新
    无聊的人用JS实现了一个简单的打地鼠游戏
  • 原文地址:https://www.cnblogs.com/flipped/p/5792694.html
Copyright © 2020-2023  润新知