最大流(二)—— SAP算法

直接上代码

#include<vector>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<queue>
#define numm ch-48
#define pd putchar(‘ ‘)
#define pn putchar(‘\n‘)
#define pb push_back
#define fi first
#define se second
#define fre1 freopen("1.txt","r",stdin)
#define fre2 freopen("2.txt","w",stdout)
using namespace std;
template <typename T>
void read(T &res) {
    bool flag=false;char ch;
    while(!isdigit(ch=getchar())) (ch==‘-‘)&&(flag=true);
    for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm);
    flag&&(res=-res);
}
template <typename T>
void write(T x) {
    if(x<0) putchar(‘-‘),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+‘0‘);
}
const int maxm=8000010;     ///有反向边,边数要开两倍
const int maxn=1000010;
const int inf=0x3f3f3f3f;
const int INF=0x7fffffff;
typedef long long ll;
struct node {   ///链式前向星
    ll c;
    int to,net;
}e[maxm];
int head[maxn],cur[maxn],numh[maxn],h[maxn],pre[maxn];
///head:链式前向星头结点数组
///cur:当前弧数组
///numh:GAP优化的统计高度数量数组
///h:距离标号数组
///pre:前驱数组
int n,cnt=0;
void init() {
//    cnt=0;
//    for(int i=1;i<=n;i++)   ///单测试用例可不用
//        h[i]=0,numh[i]=0;
    for(int i=1;i<=n;i++)
        head[i]=-1,pre[i]=-1;
}
void add(int u,int v,ll c) {
    e[cnt].to=v;
    e[cnt].c=c;
    e[cnt].net=head[u];
    head[u]=cnt++;
}
ll SAP_Max_Flow(int st,int ed) {
    ll max_flows=0;  ///最大流
    int i,u=st;
    numh[0]=n;
    for(int i=1;i<=n;i++)
        cur[i]=head[i];
    while(h[st]<n) { ///h[st]>=N时,网络中肯定出现了GAP(分层)
        if(u==ed) {
            int neck;   ///瓶颈
            ll minn=INF;
            for(i=st;i!=ed;i=e[cur[i]].to)
                if(minn>e[cur[i]].c) {
                    minn=e[cur[i]].c;
                    neck=i;
                }
            for(i=st;i!=ed;i=e[cur[i]].to) {
                int tmp=cur[i];
                e[tmp].c-=minn;
                e[tmp^1].c+=minn;
            }
            max_flows+=minn;
            u=neck;
        }
        for(i=cur[u];i!=-1;i=e[i].net)
            if(e[i].c&&h[u]==h[e[i].to]+1)
                break;      ///寻找可行弧
        if(i!=-1) {
            cur[u]=i;
            pre[e[i].to]=u;
            u=e[i].to;
        }
        else {
            if(--numh[h[u]]==0) break;
            cur[u]=head[u];
            int tmp;
            for(tmp=n,i=head[u];i!=-1;i=e[i].net)
                if(e[i].c)
                   tmp=min(tmp,h[e[i].to]);
            h[u]=tmp+1;
            numh[h[u]]++;
            if(u!=st) u=pre[u]; ///重标号并从当前点前驱重新增广
        }
    }
    return max_flows;
}
int main()
{
    int st,m,ed;
    read(n),read(m),read(st),read(ed);
    init();
    for(int i=1;i<=m;i++) {
        int u,v;
        ll c;
        read(u),read(v),read(c);
        add(u,v,c);
        add(v,u,0);     ///建立反向边
    }
    write(SAP_Max_Flow(st,ed));
    return 0;
}
///SAP算法:GAP优化+当前弧优化

  

原文地址:https://www.cnblogs.com/wuliking/p/11200564.html

时间: 2024-12-18 02:47:30

最大流(二)—— SAP算法的相关文章

最大流之sap算法

若有向图G = (V , E)满足下列条件: 1.有且仅有一个顶点S,它的入度为 0 ,这个顶点称为源点. 2.有且仅有一个顶点T,它的出度为 0 ,这个顶点称为汇点. 3.每一条弧都有一个非负数,叫做这条边的容量,边(Vi , Vj)的容量用 Cij 来表示. 则此有向图称为网络流图,记为 G = ( V , E , C) ; 对于网络流图G中,每一条弧( i , j )都给定一个非负数Fij,对于一组数据满足下面三个条件时,称为可行流: 1.对于每条弧都有 Fij < Cij ; 2.出了源

hdu3572Task Schedule 最大流,判断满流 优化的SAP算法

PS:多校联赛的题目质量还是挺高的.建图不会啊,看了题解才会的. 参考博客:http://blog.csdn.net/luyuncheng/article/details/7944417 看了上面博客里的题解,思路就有了.不过建图还是有点麻烦.我把源点设为n+1 (不想从0开始,不修改模版),汇点就是n+2+MAX,其中MAX是题目中Ei的最大值. 这题,我有疑问:优化过的SAP算法的时间复杂度是O(m*n^2),此题的n最大为1000,m为50万,时间超过5亿了.1s的时限居然过了. 其中有个

sap 算法心得

2014 11 13 今天接触了sap算法,感觉收获很多,写一些心得. 上网查sap,“设点i的标号为D[i],那么如果将满足D[i]=D[j]+1的弧(i,j)叫做允许弧,且增广时只走允许弧,那么就可以达到“怎么走都是最短路”的效果”.其实就是dinic 分层次的思想,d[i]即为当前点到汇点的距离,d数组给所有点分层.(如果不清楚自行查找) 维护距离标号的方法:当找增广路过程中发现某点出发没有允许弧时,将这个点的距离标号设为由它出发的所有弧的终点的距离标号的最小值加一.这种维护距离标号的方法

最大流 Dinic + Sap 模板

不说别的,直接上模板. Dinic+当前弧优化: struct Edge{ int x,y,c,ne; }e[M*2]; int be[N],all; int d[N],q[N]; int stack[N],top;//栈存的是边 int cur[N];//当前弧优化 void add(int x, int y, int z)//需保证相反边第一个为偶数 { e[all].x=x; e[all].y=y; e[all].c=z; e[all].ne=be[x]; be[x]=all++; e[a

垃圾回收GC:.Net自己主动内存管理 上(二)内存算法

垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己主动内存管理 上(三)终结器 前言 .Net下的GC全然攻克了开发人员跟踪内存使用以及控制释放内存的窘态.然而,你或午想要理解GC是怎么工作的.此系列文章中将会解释内存资源是怎么被合理分配及管理的,并包括很具体的内在算法描写叙述.同一时候.还将讨论GC的内存清理流程及什么时清理,怎么样强制清理. 内

垃圾回收GC:.Net自动内存管理 上(二)内存算法

垃圾回收GC:.Net自动内存管理 上(二)内存算法 垃圾回收GC:.Net自动内存管理 上(一)内存分配 垃圾回收GC:.Net自动内存管理 上(二)内存算法 前言 .Net下的GC完全解决了开发者跟踪内存使用以及控制释放内存的窘态.然而,你或午想要理解GC是怎么工作的.此系列文章中将会解释内存资源是怎么被合理分配及管理的,并包含非常详细的内在算法描述.同时,还将讨论GC的内存清理流程及什么时清理,怎么样强制清理. 内存算法 GC检测用于查看堆中是否有对象不再被程序使用.如果这样的对象存在,这

Hihocoder #1098 : 最小生成树二&#183;Kruscal算法 ( *【模板】 )

#1098 : 最小生成树二·Kruscal算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 随着小Hi拥有城市数目的增加,在之间所使用的Prim算法已经无法继续使用了——但是幸运的是,经过计算机的分析,小Hi已经筛选出了一些比较适合建造道路的路线,这个数量并没有特别的大. 所以问题变成了——小Hi现在手上拥有N座城市,且已知其中一些城市间建造道路的费用,小Hi希望知道,最少花费多少就可以使得任意两座城市都可以 通过所建造的道路互相到达(假设有A.B.C三座城市

最短路径算法之二——Dijkstra算法

Dijkstra算法 Dijkstra算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止. 注意该算法要求图中不存在负权边. 首先我们来定义一个二维数组Edge[MAXN][MAXN]来存储图的信息. 这个图的Edge数组初始化以后为 我们还需要用一个一维数组dis来存储1号顶点到其余各个顶点的初始路程,如下. 这个dis数组中存的是最短路的估计值. 通过Dijkstra算法来松弛后,dis存的为从初始点到各点的精确值(最短路径)了. Dijkstra算法实现如下(以HDU1548为例

hihoCoder - hiho一下 第二十七周 - A - 最小生成树二&#183;Kruscal算法

题目1 : 最小生成树二·Kruscal算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 随着小Hi拥有城市数目的增加,在之间所使用的Prim算法已经无法继续使用了--但是幸运的是,经过计算机的分析,小Hi已经筛选出了一些比较适合建造道路的路线,这个数量并没有特别的大. 所以问题变成了--小Hi现在手上拥有N座城市,且已知其中一些城市间建造道路的费用,小Hi希望知道,最少花费多少就可以使得任意两座城市都可以通过所建造的道路互相到达(假设有A.B.C三座城市,只需