avatar
fireworks99
keep hungry keep foolish

洛谷 P3381 最小费用最大流(模板)

最小费用最大流

原来最小费用最大流只是在最小费用流的基础上去掉固定流f,任其找最短路去增广,直到不能找到最短路了(dis[t] == INF)就退出

洛谷P3381最小费用最大流

Dijkstra is also slow

#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
const int N = 5005;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> P;///first:最短距离 second:节点编号
typedef long long ll;

struct edge{ int to, w, cap, rev; };

int n, m, s, t;
ll flow, res;
vector<edge> vec[N];
int h[N], dis[N];///节点的势 最短距离
int fro_v[N], fro_e[N];///vector 的 第一维和第二维
///用于确定最短路中点k前面那条边

void add(int from, int to, int w, int cap)
{
    int from_sz = vec[from].size(), to_sz = vec[to].size();
    vec[from].push_back( (edge){ to, w, cap, to_sz } );
    vec[to].push_back( (edge){ from, -w, 0, from_sz } );
}

void min_cost_flow(int s, int t)
{
    memset(h, 0, sizeof(h));
    while(1)
    {
        priority_queue<P, vector<P>, greater<P> > q;
        memset(dis, INF, sizeof(dis));
        dis[s] = 0;
        q.push(P(0, s));
        while(!q.empty())
        {
            P now = q.top();
            q.pop();
            int to = now.second;
            if(dis[to] < now.first)
                continue;
            for(int i = 0; i < vec[to].size(); ++i)
            {
                edge & nxt = vec[to][i];
                if(nxt.cap > 0 && dis[nxt.to] > dis[to] + nxt.w + h[to] - h[nxt.to])
                {
                    dis[nxt.to] = dis[to] + nxt.w + h[to] - h[nxt.to];
                    fro_v[nxt.to] = to;
                    fro_e[nxt.to] = i;
                    q.push(P(dis[nxt.to], nxt.to));
                }
            }
        }
        if(dis[t] == INF)
            return ;
        for(int v = 0; v <= n; ++v)
            h[v] += dis[v];

        int d = INF;
        for(int v = t; v != s; v = fro_v[v])
            d = min(d, vec[ fro_v[v] ][ fro_e[v] ].cap);

        flow += d;
        res += d * h[t];///There is a h[t] in Dijkstra, not a dis[t](in Bellman_Ford).
        for(int v = t; v != s; v = fro_v[v])///更新残余网络,建反向边
        {
            edge & nxt = vec[ fro_v[v] ][ fro_e[v] ];
            nxt.cap -= d;
            vec[v][nxt.rev].cap += d;
        }
    }
    return ;
}

int main()
{
    scanf("%d%d%d%d", &n, &m, &s, &t);
    int ui, vi, wi, fi;
    for(int i = 0; i < m; ++i)
    {
        scanf("%d%d%d%d", &ui, &vi, &wi, &fi);
        add(ui, vi, fi, wi);
    }
    min_cost_flow(s, t);
    cout << flow << ' ' << res << '\n';
    return 0;
}
Site by Baole Zhao | Powered by Hexo | theme PreciousJoy