zoukankan      html  css  js  c++  java
  • 费用流——网络流板子

    今天学了一种网络流,叫费用流。就是把网络最大流的每一条边上加一个权值,然后在网络最大流中找一条权值最小的边。题意就是这样,但是操作起来好像不是很好做。

    怎么办呢?其实就是找增广路的方法不一样,原来网络流通过bfs找增广路,这里我们通过spfa找增广路。怎么找呢?其实就是跑一遍·spfa,将最小的路径去掉然后再来一遍,那个最小的路径就是增广路。

    代码实现有一定难度,我通过各种努力终于搞出来了(一开始快读错了。。。负数读的是错的。。。)

    题目描述
    
    如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。
    输入输出格式
    输入格式:
    
    第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。
    
    接下来M行每行包含四个正整数ui、vi、wi、fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi。
    
    输出格式:
    
    一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用。
    
    输入输出样例
    输入样例#1: 复制
    
    4 5 4 3
    4 2 30 2
    4 3 20 3
    2 3 20 1
    2 1 30 9
    1 3 40 5
    
    输出样例#1: 复制
    
    50 280

    代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    using namespace std;
    #define duke(i,a,n) for(int i = a;i <= n;i++)
    #define lv(i,a,n) for(int i = a;i >= n;i--)
    #define maxn 100010
    template <class T>
    void read(T &x)
    {
        char c;
        bool op = 0;
        while(c = getchar(),c > '9' || c < '0')
            if(c == '-') op = 1;
        x = c - '0';
        while(c = getchar(),c <= '9' && c >= '0')
            x = x * 10 + c - '0';
        if(op == 1)
            x = -x;
    }
    bool vis[maxn];
    int n,m,s,t,x,y,z,f,dis[maxn],pre[maxn],last[maxn],flow[maxn],maf,mic;
    //dis最小花费;pre每个点的前驱;last每个点的所连的前一条边;flow源点到此处的流量
    struct Edge
    {
        int to,nxt,flow,dis;//flow流量 dis花费
    } a[maxn];
    int head[maxn],len;
    queue <int> q;
    void add(int from,int to,int flow,int dis)
    {
        a[++len].nxt=head[from];
        a[len].to=to;
        a[len].flow=flow;
        a[len].dis=dis;
        head[from]=len;
    }
    bool spfa(int s,int t)
    {
        memset(dis,0x7f,sizeof(dis));
        memset(flow,0x7f,sizeof(flow));
        memset(vis,0,sizeof(vis));
        q.push(s);
        vis[s]=1;
        dis[s]=0;
        pre[t]=-1;
        while (!q.empty())
        {
            int now=q.front();
            q.pop();
            vis[now]=0;
            for (int i=head[now]; i!=-1; i=a[i].nxt)
            {
                if (a[i].flow>0 && dis[a[i].to]>dis[now]+a[i].dis)//正边
                {
                    dis[a[i].to]=dis[now]+a[i].dis;
                    pre[a[i].to]=now;
                    last[a[i].to]=i;
                    flow[a[i].to]=min(flow[now],a[i].flow);//
                    if (!vis[a[i].to])
                    {
                        vis[a[i].to]=1;
                        q.push(a[i].to);
                    }
                }
            }
        }
        return pre[t]!=-1;
    }
    void max_flow()
    {
        while (spfa(s,t))
        {
            int now=t;
            maf+=flow[t];
            mic+=flow[t]*dis[t];
            while (now!=s)
            {
                a[last[now]].flow-=flow[t];//flow和dis容易搞混
                a[last[now]^1].flow+=flow[t];
                now=pre[now];
            }
        }
    }
    int main()
    {
        memset(head,-1,sizeof(head));
        len = -1;
        read(n);read(m);read(s);read(t);
        duke(i,1,m)
        {
            read(x);read(y);read(z);read(f);
            add(x,y,z,f);
            add(y,x,0,-f);
        }
        max_flow();
        printf("%d %d
    ",maf,mic);
        return 0;
    }
  • 相关阅读:
    操作系统01_进程和线程管理
    数据库02_字段类型
    鲁滨逊漂流记游戏
    查找数N二进制中1的个数(JS版 和 Java版)
    js中的call、apply
    jQuery对象与Dom对象的相互转换
    jndi配置数据源
    关于JS中变量的作用域-实例
    重写equals()方法时,需要同时重写hashCode()方法
    String与StringBuilder
  • 原文地址:https://www.cnblogs.com/DukeLv/p/9420190.html
Copyright © 2011-2022 走看看