sap 算法心得

2014 11 13

今天接触了sap算法,感觉收获很多,写一些心得。

上网查sap,“设点i的标号为D[i],那么如果将满足D[i]=D[j]+1的弧(i,j)叫做允许弧,且增广时只走允许弧,那么就可以达到“怎么走都是最短路”的效果”。其实就是dinic 分层次的思想,d【i】即为当前点到汇点的距离,d数组给所有点分层。(如果不清楚自行查找)

维护距离标号的方法:当找增广路过程中发现某点出发没有允许弧时,将这个点的距离标号设为由它出发的所有弧的终点的距离标号的最小值加一。这种维护距离标号的方法的正确性我就不证了。由于距离标号的存在,由于“怎么走都是最短路”,所以就可以采用DFS找增广路,用一个栈保存当前路径的弧即可。当某个点的距离标号被改变时,栈中指向它的那条弧肯定已经不是允许弧了,所以就让它出栈,并继续用栈顶的弧的端点增广。还有一种在常数上有所优化的写法是改变距离标号时把当前弧设为那条提供了最小标号的弧。当前弧的写法之所以正确就在于任何时候我们都能保证在邻接表中当前弧的前面肯定不存在允许弧。

这里重点讲二个优化。

1 当前弧:di【i】 记录以第i个点为开头的当前边的另一节点。注意his数组 ,它记录了当前路径中的最小值,防止因为aug的变化覆盖以前的结果。

2 gap优化:vh【i】 记录距离为i的节点个数。如果vh【i】=0  ,s、t就不连通,退出。当把一个节点的距离由x改为y时,inc【y】dec【x】。

下面给出程序:

var
flag:boolean;
jl,min,flow,aug,j,m,n,tmp,a,b,c,i:longint;
his,pre,dis,vh,di:array[0..1024] of longint;
map:array[1..1024,1..1024] of longint;
begin
readln(m,n);
for i:=1 to m do
begin
readln(a,b,c);
inc(map[a,b],c);
end;
vh[0]:=n;
for i:=1 to n do di[i]:=1;
i:=1;
aug:=maxlongint;
while dis[1]<n do
begin
his[i]:=aug;
flag:=false;
for j:=di[i] to n do
begin
if (map[i,j]>0)and(dis[j]+1=dis[i]) then
begin
flag:=true;
di[i]:=j;
if map[i,j]<aug then aug:=map[i,j];
pre[j]:=i;
i:=j;
if i=n then
begin
inc(flow,aug);
while i<>1 do
begin
tmp:=i;
i:=pre[i];
dec(map[i,tmp],aug);
inc(map[tmp,i],aug);
end;
aug:=maxlongint;
end;
break;
end;
end;
if flag then continue;
min:=n-1;
for j:=1 to n do
begin
if (map[i,j]>0)and(dis[j]<min) then begin jl:=j;min:=dis[j];end;
end;
di[i]:=jl;
dec(vh[dis[i]]);
if vh[dis[i]]=0 then break;
dis[i]:=min+1;
inc(vh[dis[i]]);
if i<>1 then begin i:=pre[i];aug:=his[i];end;
end;
write(flow);
end.

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

sap 算法心得的相关文章

《算法心得》一点整理

最近在图书馆看到本神书<算法心得:高效算法的奥秘>,主要讲解计算机算法的,强调编译器优化和计算机体系结构设计的.虽然看的不大懂,但还是给自己增长了见识和知识.少许整理些自己感兴趣的算法,以备后续温故知新. 1. 操作最右边的位元 a. 将字组中值为1且最靠右的位元置0,如果不存在值为1的位元,则全部结果为0(例如 0101 1110 => 0101 1100): x & (x-1) 这个操作可以判断无符号证书是不是2的幂或者0. b. 将字组中值为0且最靠右的位元置1,如果不存在

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算法

若有向图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.出了源

我的新书《编程之法:面试和算法心得》已经上市

我的新书<编程之法:面试和算法心得>已经上市 经过一天一天.一月一月.一年一年漫长的等待,我的新书终于上架开卖了! 异步社区:http://www.epubit.com.cn/book/details/4051.互动出版网(7.7折且包邮且移动端首单再减5元):http://product.china-pub.com/4880112.京东预售:http://item.jd.com/11786791.html,很快就能抢购. 1 新书上市7天 10月13日晚上,拿到<编程之法>第一本

编程之法:面试和算法心得(寻找和为定值的多个数)

内容全部来自编程之法:面试和算法心得一书,实现是自己写的使用的是java 题目描述 输入两个整数n和sum,从数列1,2,3.......n 中随意取几个数,使其和等于sum,要求将其中所有的可能组合列出来. 分析与解法 解法一 注意到取n,和不取n个区别即可,考虑是否取第n个数的策略,可以转化为一个只和前n-1个数相关的问题. 如果取第n个数,那么问题就转化为"取前n-1个数使得它们的和为sum-n",对应的代码语句就是sumOfkNumber(sum - n, n - 1): 如果

编程之法:面试和算法心得(荷兰国旗)

内容全部来自编程之法:面试和算法心得一书,实现是自己写的使用的是java 题目描述 拿破仑席卷欧洲大陆之后,代表自由,平等,博爱的竖色三色旗也风靡一时.荷兰国旗就是一面三色旗(只不过是横向的),自上而下为红白蓝三色. 该问题本身是关于三色球排序和分类的,由荷兰科学家Dijkstra提出.由于问题中的三色小球有序排列后正好分为三类,Dijkstra就想象成他母国的国旗,于是问题也就被命名为荷兰旗问题(Dutch National Flag Problem). 下面是问题的正规描述: 现有n个红白蓝

最大流(二)—— 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 fr

微软面试100题系列算法心得

微软100题系列地址 答案地址 谓之随笔,当是自己在练习此类算法的一些想法,一些心得,一些领悟,一些借鉴,当自引用之时,会附上相应的链接! 题:把二元查找树转变成排序的双向链表(树) 描述:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表.要求不能创建任何新的结点,只调整指针的指向. 思维过程[个人思维]: 1. 二元查找树是指在任何结点看来,它的左子树上的值要少于当前结点的值,而它的右子树上的值要大于当前结点的值,对于等于的值那就看自己的原则放左子树还是右子树. 2. 关于树的算法必

网络流(三)----最大流SAP算法

以  HDU 3572  Task Schedule 为例的模板 Code: #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <stack>