费用流——网络流板子

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

怎么办呢?其实就是找增广路的方法不一样,原来网络流通过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\n",maf,mic);
    return 0;
}

 

posted @ 2018-08-04 21:42  DukeLv  阅读(289)  评论(0编辑  收藏  举报