最大流 - JZOJ 4087 网络吞吐量 CQOI 2015

传送门
这道题是一道网络流裸题,也是我的第一道除了题面标明了是裸题的网络流。= =

这道题的正解就是把最短路找出来然后跑最大流就可以啦。然而我一开始写了一个最小费用最大流。果然还是没有做过题。。。所以这道题分为两部分。

①求出所有最短路上的路径
这个问题可以参照某年初赛的做法。方法是先跑一次 SPFA,然后再连接dis[i] + cost = dis[j]的边。

②最大流
不多说了。。。功力太弱。。。这里我们就先巩固一下Edmond Karps 算法吧。Dinic 和 ISAP以后再说。。。
Edmond Karps 算法是一个最短增广路算法。它的思想就是直接用BFS所以不需要 inQ 数组,因为不需要重复入队;但是也不需要 vis 数组,因为可以通过 opt(imize) 数组来判断是否走过。当然,还需要一个 pre(vious) 数组。(只是为了帮助记忆)

边的话,有 4 个属性。分别是起点终点,流量和容量。对于一般的边,容量初始值为给定容量。对于用于反向增广的反向边,容量为 0。所有边的流量一开始都是 0。

记住,所谓增广是在残量网络中增广。一次增广后,要通过 pre 数组回来改边。只需要把走过的边的流量加上 opt[t],把反向边的流量减去 opt[t]。

另外,这种边没有容量而点有容量的题目我就不多说了。拆点即可。

参考代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using std::cin;
using std::cout;
using std::endl;
typedef long long INT;
inline INT readIn()
{
    INT a = 0;
    bool minus = false;
    char ch = getchar();
    while (!(ch == '-' || ch >= '0' && ch <= '9')) ch = getchar();
    if (ch == '-')
    {
        minus = true;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        a *= 10;
        a += ch;
        a -= '0';
        ch = getchar();
    }
    if (minus) a = -a;
    return a;
}

const INT INF = (~(INT(1) << (sizeof(INT) * 8 - 1))) >> 1;
const INT maxn = 505;
const INT maxm = 100005;
INT n, N, m;

struct E
{
    INT to;
    INT cost;
    E() {}
    E(INT to, INT cost) : to(to), cost(cost) {}
};
std::vector<std::vector > es;

struct Edge
{
    INT from;
    INT to;
    INT flow;
    INT cap;

    Edge() {}
    Edge(INT from, INT to, INT cap) : from(from), to(to), flow(), cap(cap) {}
};
std::vector edges;
std::vector<std::vector > G;
void addEdge(INT from, INT to, INT cap)
{
    edges.push_back(Edge(from, to, cap));
    edges.push_back(Edge(to, from, 0));
    INT s = edges.size();
    G[from].push_back(s - 2);
    G[to].push_back(s - 1);
}

INT s, t;

INT dis[maxn];
void SPFA_INIT()
{
    memset(dis, 0x3f, sizeof(dis));
    dis[1] = 0;

    std::queue q;
    std::vector<bool> inQ(n + 1);
    q.push(1);
    inQ[1] = true;
    while(!q.empty())
    {
        INT from = q.front();
        q.pop();
        inQ[from] = false;

        for(int i = 0; i < es[from].size(); i++)
        {
            E& e = es[from][i];
            INT to = e.to;
            INT cost = e.cost;
            if(dis[to] > dis[from] + cost)
            {
                dis[to] = dis[from] + cost;
                if(!inQ[to])
                {
                    inQ[to] = true;
                    q.push(to);
                }
            }
        }
    }
}
void SPFA_BUILD()
{
    std::queue q;
    std::vector<bool> inQ(n + 1);
    q.push(1);
    inQ[1] = true;
    while(!q.empty())
    {
        INT from = q.front();
        q.pop();
        inQ[from] = false;

        for(int i = 0; i < es[from].size(); i++)
        {
            E& e = es[from][i];
            INT to = e.to;
            INT cost = e.cost;
            if(dis[to] == dis[from] + cost)
            {
                addEdge(from * 2, to * 2 - 1, INF);
                if(!inQ[to])
                {
                    inQ[to] = true;
                    q.push(to);
                }
            }
        }
    }
}

INT EdmondKarps(INT s, INT t)
{
    std::vector pre(N + 1);
    std::vector opt(N + 1);

    std::queue q;
    opt[s] = INF;
    q.push(s);

    while(!q.empty())
    {
        INT from = q.front();
        q.pop();
        for(int i = 0; i < G[from].size(); i++)
        {
            Edge& e = edges[G[from][i]];
            if(e.flow < e.cap && !opt[e.to])
            {
                opt[e.to] = std::min(opt[from], e.cap - e.flow);
                pre[e.to] = G[from][i];
                q.push(e.to);
            }
        }
        if(opt[t]) break;
    }

    if(!opt[t]) return 0;
    for(int i = t; i != s; i = edges[pre[i]].from)
    {
        edges[pre[i]].flow += opt[t];
        edges[pre[i] ^ 1].flow -= opt[t];
    }
    return opt[t];
}

INT MaxFlow()
{
    INT s = 2;
    INT t = 2 * n - 1;
    INT flow = 0;

    while(INT f = EdmondKarps(s, t)) flow += f;
    return flow;
}

void run()
{
    n = readIn();
    m = readIn();
    N = n << 1;
    es.resize(n + 1);
    G.resize(N + 1);

    for(int i = 1; i <= m; i++)
    {
        INT from = readIn();
        INT to = readIn();
        INT cost = readIn();
        es[from].push_back(E(to, cost));
        es[to].push_back(E(from, cost));
    }
    SPFA_INIT();
    SPFA_BUILD();

    for(int i = 1; i <= n; i++)
    {
        INT cap = readIn();
        addEdge(i * 2 - 1, i * 2, cap);
        addEdge(i * 2, i * 2 - 1, cap);
    }

    cout << MaxFlow() << endl;
}

int main()
{
#ifndef JUDGE
    freopen("network.in", "r", stdin);
    freopen("network.out", "w", stdout);
#endif
    run();
    return 0;
}

你可能感兴趣的:(OI,网络流,图)