码迷,mamicode.com
首页 > 其他好文 > 详细

习题:费用流(网络流)

时间:2019-12-12 20:02:37      阅读:136      评论:0      收藏:0      [点我收藏+]

标签:lin   define   pre   efi   +=   memset   mat   i++   return   

题目

传送门

思路

这道题题目是费用流

但实际上跟费用流没有一点关系,

我们首先思考Bob的最优策略,

对于Bob来说

\(ans=\sum_{i=1}^{m} w_i*flow_i\)

我们发现对于Bob,

最优策略一定是将所有的单位花费全都怼在流量最大的一条边上

知道了Bob的最优策略之后,

对于Alice而言,就是将流量最大的一条边的流量尽可能小,

同时保证最大流不变

很明显,此方式是有单调性的

所以我们可以考虑二分

将二分的mid用来限制每一条边的最大容量

之后再跑最大流来检验就行了

代码

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<climits>
using namespace std;
const double eps=1e-9;
struct node
{
    int u,v;
    double w;
};
int n,m;
double p;
double l,r,mid;
double max_f;
vector<node>v;
struct networt_flow_isap
{
    #define MAXN 205
    double c[MAXN][MAXN];
    int d[MAXN];
    int vd[MAXN];
    double maxx;
    int s,t;
    vector<int> g[MAXN];
    #undef MAXN
    void add(int u,int v,double w)
    {
        g[u].push_back(v);
        g[v].push_back(u);
    }
    void init()
    {
        maxx=0;
        memset(c,0,sizeof(c));  
        memset(d,0,sizeof(d));
        memset(vd,0,sizeof(vd));
        for(int i=1;i<=n;i++)
            g[i].clear();

    }
    double dfs(int u,double f)
    {
        if(u==t)
            return f;
        double minn=0,summ=0;
        int id=n-1;
        for(int i=0;i<g[u].size();i++)
        {
            int v=g[u][i];
            if(c[u][v]>0)
            {
                if(d[u]==d[v]+1)
                {
                    minn=min(f-summ,c[u][v]);
                    minn=dfs(v,minn);
                    c[u][v]-=minn;
                    c[v][u]+=minn;
                    summ+=minn;
                    if(d[s]>=n)
                        return summ;
                    if(summ==f)
                        break;
                }
                if(d[v]<id)
                    id=d[v];
            }
        }
        if(summ==0)
        {
            vd[d[u]]--;
            if(!vd[d[u]])
                d[s]=n;
            d[u]=id+1;
            vd[d[u]]++;
        }
            
        return summ;
    }
    double isap(int S,int T)
    {
        memset(d,0,sizeof(d));
        memset(vd,0,sizeof(vd));
        s=S;
        t=T;
        vd[0]=n;
        maxx=0;
        while(d[s]<n)
            maxx+=dfs(s,(1ll<<60)/2);
        return maxx;
    }
}g;
void init(double cnt)
{
    memset(g.c,0,sizeof(g.c));
    for(int i=0;i<v.size();i++)
    {
        g.c[v[i].u][v[i].v]+=min(v[i].w,cnt);
        g.c[v[i].v][v[i].u]=0;
    }
}
double f_abs(double x)
{
    if(x<0)
        return -x;
    return x;
}
bool check(double cnt)
{
    init(cnt);
    double ans=g.isap(1,n);
    //cout<<cnt<<' '<<ans<<'\n';
    if(f_abs(ans-max_f)<eps)
        return 1;
    return 0;
}
int main()
{
    cin>>n>>m>>p;
    for(int i=1;i<=m;i++)
    {
        int x,y;
        double z;
        cin>>x>>y>>z;
        v.push_back((node){x,y,z});
        g.add(x,y,z);
    }
    init(1e9);
    max_f=g.isap(1,n);
    cout<<max_f<<'\n';
    l=0;
    r=1e9;
    while(l+eps<r)
    {
        mid=(l+r)/2;
        if(check(mid))
            r=mid;
        else
            l=mid;
    }
    printf("%.5lf",mid*p);
    return 0;
}

习题:费用流(网络流)

标签:lin   define   pre   efi   +=   memset   mat   i++   return   

原文地址:https://www.cnblogs.com/loney-s/p/12031008.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!