网络流算法与建模总结

【算法】

1.最大流

(1) 容量限制:对于∀u,v∈V ,要求 f (u,v) ≤ c(u,v)。

(2) 反对称性:对于∀u,v∈V ,要求 f (u,v) = − f (v,u)。

(3) 流量平衡:对于∀u∈V −{s,t},要求∑f(u,v)=0。

dinic

  1. 根据残量网络计算层次图。
  2. 在层次图中使用DFS沿阻塞流(不考虑反向弧时的极大流 层次图中的)进行增广直到不存在增广路
  3. 重复以上步骤直到无法增广

int cur[N];
int vis[N],d[N],q[N],head,tail;
bool bfs(){
    memset(vis,0,sizeof(vis));
    memset(d,0,sizeof(d));
    head=tail=1;
    q[tail++]=s;d[s]=0;vis[s]=1;
    while(head!=tail){
        int u=q[head++];
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(!vis[v]&&e[i].c>e[i].f){
                vis[v]=1;d[v]=d[u]+1;
                q[tail++]=v;
                if(v==t) return 1;
            }
        }
    }
    return 0;
}
int dfs(int u,int a){
    if(u==t||a==0) return a;
    int flow=0,f;
    for(int &i=cur[u];i;i=e[i].ne){
        int v=e[i].v;
        if(d[v]==d[u]+1&&(f=dfs(v,min(a,e[i].c-e[i].f)))>0){
            flow+=f;
            e[i].f+=f;
            e[((i-1)^1)+1].f-=f;
            a-=f;
            if(a==0) break;
        }
    }
    return flow;
}
int dinic(){
    int flow=0;
    while(bfs()){
        for(int i=s;i<=t;i++) cur[i]=h[i];
        flow+=dfs(s,INF);
    }
    return flow;
}

2.最小割

最大流的对偶问题

流网络G =(V,E)的割(cut)[S,T]将点集V划分为S和T(T =V −S)两个部分,

使得源s∈S且汇t∈T。符号[S,T]代表一个边集合{ u,v | u,v ∈E,u∈S,v∈T}。

穿过割 [S,T]的净流(net flow)定义为 f (S,T),割[S,T]的容量(capacity)定义为c(S,T),一般 记为c[S,T]。

一个网络的最小割(minimum cut)也就是该网络中容量最小的割。

增广路算法结束时,所有还有流量(从s走)的点组成S,没有流量的点组成T

最大流的流量就是最小割的容量

3.最小费用最大流

(1)spfa费用流

用spfa找最短路来增广

保存pre[i]和pos[i]分别是最短路中的父节点和入边

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=5005,M=5e4+5,INF=1e9;
int read(){
    char c=getchar();int x=0,f=1;
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘; c=getchar();}
    return x*f;
}
int n,m,s,t,u,v,w,c;
struct edge{
    int v,ne,c,f,w;
}e[M<<1];
int cnt,h[N];
inline void ins(int u,int v,int c,int w){
    cnt++;
    e[cnt].v=v;e[cnt].c=c;e[cnt].f=0;e[cnt].w=w;
    e[cnt].ne=h[u];h[u]=cnt;
    cnt++;
    e[cnt].v=u;e[cnt].c=0;e[cnt].f=0;e[cnt].w=-w;
    e[cnt].ne=h[v];h[v]=cnt;
}
int d[N],pre[N],pos[N],q[N],head=1,tail=1,inq[N];
inline void lop(int &x){if(x==N) x=1;else if(x==0) x=N-1;}
bool spfa(){
    memset(d,127,sizeof(d));
    d[s]=0;pre[t]=-1;
    head=tail=1;
    memset(inq,0,sizeof(inq));
    q[tail++]=s;inq[s]=1;
    while(head!=tail){
        int u=q[head++];lop(head);inq[u]=0;
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v,w=e[i].w;
            if(d[v]>d[u]+w&&e[i].c>e[i].f){
                d[v]=d[u]+w;
                pre[v]=u;
                pos[v]=i;
                if(!inq[v]){
                    if(d[v]<d[q[head]]) head--,lop(head),q[head]=v;
                    else q[tail++]=v,lop(tail);
                    inq[v]=1;
                }
            }
        }
    }
    return pre[t]==-1?0:1;
}
void mcmf(){
    ll flow=0,cost=0;
    while(spfa()){
        int f=INF;
        for(int i=t;i!=s;i=pre[i]) f=min(f,e[pos[i]].c-e[pos[i]].f);
        flow+=f;
        cost+=f*d[t];
        for(int i=t;i!=s;i=pre[i]){
            e[pos[i]].f+=f;
            e[((pos[i]-1)^1)+1].f-=f;
        }
    }
    printf("%lld %lld",flow,cost);
}
int main(int argc, const char * argv[]) {
    n=read();m=read();s=read();t=read();
    for(int i=1;i<=m;i++){
        u=read();v=read();c=read();w=read();
        ins(u,v,c,w);
    }
    mcmf();
    return 0;
}

(2)zkw费用流

http://www.artofproblemsolving.com/community/c1368h1020435





【建模】

1.公平分配问题

把X分配给Y,一个X有两个Y可选,让分配到最多的最少

二分图模型,X和Y构成二分图

二分最多最少值mid

s--1-->X--1-->Y--mid-->t

看maxflow==|X|



2.最大闭合子图

定义一个有向图G = (V,E)的闭合图(closure)10是该有向图的一个点集,且该点集的所 有出边都还指向该点集。即闭合图内的任意点的任意后继也一定在闭合图中。

在原图点集的基础上增加源s和汇t;

将原图每条有向边 u,v ∈E替换为容量为c(u,v)=∞的有向边u,v ∈EN;

增加连接源s到原图每个正权点v(wv >0)的有向边s,v ∈EN,容量为c(s,v)=wv;

增加连接原图每个负权点v(wv <0)到汇t的有向边v,t ∈EN,容量为c(v,t)=−wv

(这样下来两个边权都是正数)

s--点权-->正权点----INF----负权点--|点权|-->t

胡波涛论文中有详细证明

我们也可以简单的思考最小割,要么(1)把s-->正u割了,要么(2)把负v-->t割了

(1)相当于不选择这个u,他的后继就没必要选了,同时损失wu

(2)相当于选择了u,同时选择了他的后继v,所以损失wv



3.二分图最大匹配

s--1-->X--1-->Y--1-->t



4.最小路径覆盖问题

G 的最小路径覆盖是G 的所含路径条数最少的路径覆盖。

有点逆向思考的感觉最差情况所有的点都是一条路径两个点连起来的话就少一条路径一个点拆成入点X和出点Y,构成二分图,ans=n-最大匹配数


5.

时间: 2024-11-06 16:06:57

网络流算法与建模总结的相关文章

网络流算法Dinic的Python实现

在上一篇我们提到了网络流算法Push-relabel,那是90年代提出的算法,算是比较新的,而现在要说的Dinic算法则是由以色列人Dinitz在冷战时期,即60-70年代提出的算法变种而来的,其算法复杂度为O(mn^2). Dinic算法主要思想也是基于FF算法的,改进的地方也是减少寻找增广路径的迭代次数.此处Dinitz大师引用了一个非常聪明的数据结构,Layer Network,分层网络,该结构是由BFS tree启发得到的,它跟BFS tree的区别在于,BFS tree只保存到每一层的

网络流算法--Ford-Fulkerson方法及其多种实现

原文链接:http://www.cnblogs.com/luweiseu/archive/2012/07/14/2591573.html 7. 网络流算法--Ford-Fulkerson方法及其多种实现 网络流 在上一章中我们讨论的主题是图中顶点之间的最短路径,例如公路地图上两地点之间的最短路径,所以我们将公路地图抽象为有向带权图.本章我们将对基于有向带权图的模型做进一步扩展. 很多系统中涉及流量问题,例如公路系统中车流量,网络中的数据信息流,供油管道的油流量等.我们可以将有向图进一步理解为"流

网络流算法模板

通过USACO草地排水学习了一下网络流,终于写好了几个模板. 最大流 BFS求增广路径 简述:通过BFS在网络中找出一条最短增广路径并修改流量(前向弧加可改进量X,后向弧则减去X),当不存在增广路径时得出最大流,时间效率O(nm^2). { ID: qty1272 PROG: ditch LANG: PASCAL } program ditch; var c,f:array[0..200,0..200]of longint; path,u:array[0..200]of longint; n,i

[转] 网络流算法--Ford-Fulkerson方法及其多种实现

网络流 转载自:http://www.cnblogs.com/luweiseu/archive/2012/07/14/2591573.html 在上一章中我们讨论的主题是图中顶点之间的最短路径,例如公路地图上两地点之间的最短路径,所以我们将公路地图抽象为有向带权图.本章我们将对基于有向带权图的模型做进一步扩展. 很多系统中涉及流量问题,例如公路系统中车流量,网络中的数据信息流,供油管道的油流量等.我们可以将有向图进一步理解为“流网络”(flow network),并利用这样的抽象模型求解有关流量

网络流算法Push-relabel的Python实现

网络流的背景我就不多说了,就是在一个有向图中找出最大的流量,有意思的是,该问题的对偶问题为最小割,找到一种切分,使得图的两边的流通量最小,而且通常对偶问题是原问题的一个下界,但最小割正好等于最大流,即切割的边就是最大流中各个path饱和边的一个组合.说得可能比较含糊,这里想要了解清楚还是查阅相关资料吧. 最大流最原始最经典的解法就是FF算法,算法复杂度为O(mC),C为边的容量的总和,m为边数.而今天讲的Push-relabel算法是90年代提出的高效算法,复杂度为O(n^3),其实网络流最关键

关于网络流算法(2)

了解最大流解法: 网络流的相关基础知识很容易获得,详细的有<算导>,简单的有刘汝佳<算法竞赛入门>,这里选用的也是刘的书从Page207开始的内容. 这里要补充一些值得注意的基础: 最大流问题中的三个约束条件:容量限制条件.斜对成性条件.流量平衡条件: 网络流问题中边(Edge)的有向性. 1.1 BFS算法 因为<算法竞赛入门>中的E-K算法是基于BFS遍历方法的,说是很容易找到让DFS很慢的例子所以改为BFS,自己又已经把以前看的书全部忘记了,无奈只能开这个1.1,

ISAP网络流算法

ISAP全称Improved Shortest Augmenting Path,意指在SAP算法进行优化.SAP即Edmonds-Karp算法,其具体思路是通过不断向残存网络推送流量来计算整个网络的最大流.阅读本文要求掌握网络流的基础概念,不懂的出门左拐算法导论.ISAP的时间复杂度与EK算法一致,而EK算法的时间复杂度为min(O(E|f|),O(VE^2)),其中O(E|f|)部分是因为其是在FORD-FULKERSON算法上的改进.EK算法在FF算法的基础上将随意取增广路径替换为取最短增广

关于网络流算法(3)

实现MCMF的基础上进行尝试针对题目修改代码就方便许多,这里的一个难点是如何输出MCMF对应的各条流路径(网络路径).实现了MCMF之后很长的一段时间我一直在走弯路,最后发现是自己的测试数据并不方便手算而且一开始采用的模板本身有错误,另一方面因为我之前并没有接触过图论算法,对这些现学的算法实现和运行细节不熟悉.在调整心态之后我决定使用自己设计的图作为调试用例并慢节奏地调试理解,稳扎稳打. 这里有一个博客,作者的思路与我一致,其内容对我有很大帮助. 2.1 多服务器(固定)-多消费结点.无输出的版

图论专题小结:网络流算法之ISAP算法

ISAP算法 ISAP(Improved Shortest Augument Path)算法是改进版的SAP算法,如果对效率要求很高的时候,可以用该算法. (1)概述:算法基于这样的一个事实:每次增广之后,任意结点到汇点(在残余网络中)的最短距离都不会减小.这样,我们可以利用d[i[表示结点i到汇点的距离的下界.然后再增广过程当中不断地修改这个下界.增广的时候和Dinic算法类似,只允许沿着d[i]==d[j]+1的弧(i,j)走. 不难证明,d[i[满足两个条件:(1)d[t]=0;(2)对任