• 【JZOJ3215】【SDOI2013】费用流


    ╰( ̄▽ ̄)╭

    对于一张给定的 运输网络 ,Alice 先确定一个最大流 ,如果有多种解, Alice 可以任选一种; 之后 Bob在每条边上分配单位花费 (单位花费必须是非负实数), 要求所有边的单位花费之和等于 P。总费用等于每一条边 的实际流量乘以该边的单位花费。 需要注意到, Bob在分配单位花费之前,已经知道Alice 所给出的最大流方案。

    现在 Alice 希望总费用尽量小,而Bob希望总费用尽量大。我们想知道, 如 果两个人都执行最优策略 ,最大流的值和总费用分别为多少。

    对于 100% 的测试数据: N≤100 ,M≤1000 。
    对于 100% 的测试数据: 所有点的编号在 1..N 范围内。 1≤每条边 的最大 流 量≤50000 。1≤P≤10 。给定运输网络中不会有起点和 终点 相同的边。

    (⊙ ▽ ⊙)

    显然Bob要把所有费用全部分配给实际流量最大的边。
    所以Alice在满足最大流最大之余,使得流量最大的边最小
    所以二分后再用最大流判断就可以了。

    ( ̄~ ̄)

    #include<iostream>
    #include<algorithm>
    #include<stdio.h>
    #include<math.h>
    #include<string.h>
    #define ll long long
    #define eps 10e-7
    using namespace std;
    const char* fin="ex3215.in";
    const char* fout="ex3215.out";
    const int inf=0x7fffffff;
    const int maxn=2007;
    int n,m,n1,i,j,k;
    int a[maxn][2],fi[maxn],ne[maxn],la[maxn],tot;
    double l,r,mid,va[maxn],b[maxn],Ans;
    int bz[maxn],card[maxn];
    double Abs(double a){
        return a>0?a:-a;
    }
    void add_line(int a,int b,double c){
        tot++;
        ne[tot]=fi[a];
        la[tot]=b;
        va[tot]=c;
        fi[a]=tot;
    }
    void add(int a,int b,double c){
        add_line(a,b,c);
        add_line(b,a,0);
    }
    double gap(int v,double flow){
        int i,k;
        double use=0,j;
        if (v==n) return flow;
        for (k=fi[v];k;k=ne[k])
            if (bz[la[k]]+1==bz[v] && Abs(va[k])>eps){
                j=gap(la[k],min(va[k],flow-use));
                use+=j;
                va[k]-=j;
                va[k^1]+=j;
                if (Abs(flow-use)<eps || bz[1]==n) return use;
            }
        if (!--card[bz[v]]) bz[1]=n;
        card[++bz[v]]++;
        return use;
    }
    double flow(){
        double ans=0;
        memset(card,0,sizeof(card));
        memset(bz,0,sizeof(bz));
        card[0]=n;
        while (bz[1]<n){
            ans+=gap(1,inf);
        }
        return ans;
    }
    bool judge(double MAX){
        int i,j,k;
        memset(fi,0,sizeof(fi));
        tot=1;
        for (i=1;i<=m;i++) add(a[i][0],a[i][1],min(MAX,b[i]));
        return Abs(flow()-Ans)<eps;
    }
    int main(){
        scanf("%d%d%d",&n,&m,&n1);
        tot=1;
        for (i=1;i<=m;i++) scanf("%d%d%lf",&a[i][0],&a[i][1],&b[i]),add(a[i][0],a[i][1],b[i]);
        Ans=flow();
        l=0;
        r=50000;
        while (r-l>eps){
            mid=(l+r)/2;
            if (judge(mid)) r=mid;
            else l=mid;
        }
        printf("%d
    %.4lf",int(Ans+eps),l*n1 );
        return 0;
    }

    (⊙v⊙)

    要注意的是网络流的实现时的问题:

    double gap(int v,double flow){
        int i,k;
        double use=0,j;
        if (v==n) return flow;
        for (k=fi[v];k;k=ne[k])
            if (bz[la[k]]+1==bz[v] && Abs(va[k])>eps){
                j=gap(la[k],min(va[k],flow-use));
                use+=j;
                va[k]-=j;
                va[k^1]+=j;
                if (Abs(flow-use)<eps || bz[1]==n) return use;
            }
        if (!--card[bz[v]]) bz[1]=n;
        card[++bz[v]]++;
        return use;
    }

    1.三个中两个return返回的都是use;
    2.当use==flow使,直接返回use;
    3.到达汇点,返回flow。

  • 相关阅读:
    课堂练习四
    手头软件产品的评价
    学习进度条十
    典型用户和用户场景描述
    学习进度条九
    学习进度条八
    冲刺第十天
    冲刺第九天
    冲刺第八天
    冲刺第七天
  • 原文地址:https://www.cnblogs.com/hiweibolu/p/6714790.html
Copyright © 2020-2023  润新知