网络流模版

终于找到了心仪的网络流模版


首先是Dinic


/*
Dinic 模版 (刘汝佳) 支持重边 加入当前弧优化
递归写法 如果递归爆栈 改用ISAP
*/
#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;

typedef long long ll;
typedef long double ld;

const int N = 1100;

#define INF 0xfffffff
#define met(a, b) memset(a, b, sizeof(a))

struct edge{int from, to, cap, flow;};
int n, m;  //结点 边数
vector <edge> edges; //边表
vector <int> G[N]; //邻接表 G[i][j] 结点i的第j条边在e数组中的序号
bool vis[N]; // bfs使用
int d[N]; // 从起点到i的距离
int cur[N]; //当前弧下标

void addedge (int from, int to, int cap)
{
    edges.push_back((edge){from, to, cap, 0});
    edges.push_back((edge){to, from, 0, 0});
    int tm = edges.size();
    G[from].push_back(tm-2);
    G[to].push_back(tm-1);
}
bool bfs (int s, int t)
{
    met (vis, false);
    queue <int> que;
    que.push (s);
    d[s] = 0;
    vis[s] = true;
    while (que.size())
    {
        int x = que.front(); que.pop();
        for (int i=0; i<G[x].size(); i++)
        {
            edge &e = edges[G[x][i]];
            if (!vis[e.to] && e.cap > e.flow)
            {
                vis[e.to] = true;
                d[e.to] = d[x] + 1;
                que.push(e.to);
            }
        }
    }
    return vis[t];
}

int dfs (int x, int t, int a)
{
    if (x == t || a == 0) return a;
    int flow = 0, f;
    for (int &i=cur[x]; i<G[x].size(); i++)
    {
        edge &e = edges[G[x][i]];
        if (d[x] + 1 == d[e.to] && (f = dfs(e.to, t, min(a, e.cap - e.flow))) > 0)
        {
            e.flow += f;
            edges[G[x][i] ^ 1].flow -= f;
            flow += f;
            a -= f;
            if (a == 0) break;
        }
    }
    return flow;
}

int maxflow (int s, int t)
{
    int flow = 0;
    while (bfs(s, t))
    {
        met (cur, 0);
        flow += dfs(s, t, INF);
    }
    return flow;
}


ISAP


//IASP (刘汝佳)
#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#include <vector>
#include <string>
using namespace std;

typedef long long ll;
typedef long double ld;

const int N = 1100;
const int INF = 0xfffffff;

#define met(a, b) memset(a, b, sizeof(a))

struct edge{int from, to, cap, flow;};
int n, m;  //结点 边数
vector <edge> edges; //边表
vector <int> G[N]; //邻接表 G[i][j] 结点i的第j条边在e数组中的序号
bool vis[N]; // bfs使用
int d[N]; // 从起点到i的距离
int cur[N]; //当前弧下标
int p[N]; //可增广路上的一条弧
int num[N]; //距离标号计数

void addedge (int from, int to, int cap)
{
    edges.push_back((edge){from, to, cap, 0});
    edges.push_back((edge){to, from, 0, 0});
    int tm = edges.size();
    G[from].push_back(tm-2);
    G[to].push_back(tm-1);
}

int augment (int s, int t)
{
    int x = t, a = INF;
    while (x != s)
    {
        edge &e = edges[p[x]];
        a = min (a, e.cap - e.flow);
        x = edges[p[x]].from;
    }
    x = t;
    while (x != s)
    {
        edges[p[x]].flow += a;
        edges[p[x]^1].flow -= a;
        x = edges[p[x]].from;
    }
    return a;
}
void bfs(int t) //待验证 自己补写的
{
    met (vis, false);
    queue <int> que;
    que.push (t);
    d[t] = 0;
    vis[t] = true;
    while (que.size())
    {
        int x = que.front();
        que.pop();
        for (int i=0; i<G[x].size(); i++)
        {
            edge &e = edges[G[x][i]];
            if (!vis[e.to] && e.cap > e.flow)
            {
                vis[e.to] = true;
                d[e.to] = d[x] + 1;
                que.push (e.to);
            }
        }
    }
}

int ISAP (int s, int t)
{
    int flow = 0;
    bfs (t);
  //  met (num, 0); met (d, 0); // 或者bfs
    /*初始标号可以统一设置为0 或者用bfs
    单次运行时效率相差不大 多次求解小规模网络流
    速度会有明显提升*/
    for (int i=0; i<n; i++) num[d[i]]++;
    int x = s;
    met (cur, 0);
    while (d[s] < n)
    {
        if (x == t)
        {
            flow += augment(s, t);
            x = s;
        }
        bool ok = false;
        for (int i=cur[x]; i<G[x].size(); i++)
        {
            edge &e = edges[G[x][i]];
            if (e.cap > e.flow && d[x] == d[e.to] + 1)
            {
                ok = true;
                p[e.to] = G[x][i];
                cur[x] = i;
                x = e.to;
                break;
            }
        }
        if (!ok)
        {
            int m = n - 1;
            for (int i=0; i<G[x].size(); i++)
            {
                edge &e = edges[G[x][i]];
                if (e.cap > e.flow)
                    m = min (m, d[e.to]);
            }
            if (--num[d[x]] == 0)
                break; //gap优化
            num[d[x] = m + 1]++;
            cur[x] = 0;
            if (x != s) x = edges[p[x]].from;
        }
    }
    return flow;
}


//最小费用最大流
#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#include <vector>
#include <string>
using namespace std;

typedef long long ll;
typedef long double ld;

const int N = 1100;
const int INF = 0xfffffff;

#define met(a, b) memset(a, b, sizeof(a))

struct edge
{
    int from, to, cap, flow, cost;
};
int n, m;  //结点 边数
vector <edge> edges; //边表
vector <int> G[N]; //邻接表 G[i][j] 结点i的第j条边在e数组中的序号
int inq[N]; //是否在队列中
int d[N];  //bellman-ford 距离
int p[N];   //上一条弧
int a[N];    //可改进量

void init ()
{
    for (int i=0; i<n; i++)
        G[i].clear();
    edges.clear();
}

void addedge (int from, int to, int cap, int cost)
{
    edges.push_back((edge)
    {
        from, to, cap, 0, cost
    });
    edges.push_back((edge)
    {
        to, from, 0, 0, -cost
    });
    int tm = edges.size();
    G[from].push_back(tm-2);
    G[to].push_back(tm-1);
}

bool bellmanFord (int s, int t, int &flow, int &cost)
{
    /*for (int i=0; i<n; i++)
        d[i] = INF;*/
    fill (d, d + n, INF);
    met (inq, 0);
    d[s] = 0;
    inq[s] = 1;
    p[s] = 0;
    a[s] = INF;

    queue <int> que;
    que.push (s);
    while (que.size())
    {
        int u = que.front();
        que.pop();
        inq[u] = 0;
        for (int i=0; i<G[u].size(); i++)
        {
            edge &e = edges[G[u][i]];
            if (e.cap > e.flow && d[e.to] > d[u] + e.cost)
            {
                d[e.to] = d[u] + e.cost;
                p[e.to] = G[u][i];
                a[e.to] = min (a[u], e.cap - e.flow);
                if (!inq[e.to])
                {
                    que.push (e.to);
                    inq[e.to] = 1;
                }
            }
        }
    }
    if (d[t] == INF) return false;
    flow += a[t];
    cost += d[t] * a[t];
    int u = t;
    while (u != s)
    {
        edges[p[u]].flow += a[t];
        edges[p[u]^1].flow -= a[t];
        u = edges[p[u]].from;
    }
    return true;
}

int Mincost (int s, int t)
{
    int flow = 0, cost = 0;
    while (bellmanFord(s, t, flow, cost));
    return cost;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值