dinic算法学习(以poj1273为例)

Dinic 算法模板

Dinic算法是一种比较容易实现的,相对比较快的最大流算法。

求最大流的本质,就是不停的寻找增广路径。直到找不到增广路径为止。

对于这个一般性的过程,Dinic算法的优化如下:

(1)Dinic算法首先对图进行一次BFS,然后在BFS生成的层次图中进行多次DFS。

层次图的意思就是,只有在BFS树中深度相差1的节点才是连接的。

这就切断了原有的图中的许多不必要的连接。很牛逼!

这是需要证明的,估计证明也很复杂。

(2)除此之外,每次DFS完后,会找到路径中容量最小的一条边。

在这条边之前的路径的容量是大于等于这条边的容量的。

那么从这条边之前的点,可能引发出别的增广路径。

比如说 S -> b -> c -> d -> T 是一条增广路径,容量最小的边是 b -> c。

可能存在一条 S -> b -> e -> f -> g -> T 这样的增广路径。

这样的话,在找到第一条增广路径后,只需要回溯到 b 点,就可以继续找下去了。

这样做的好处是,避免了找到一条路径就从头开始寻找另外一条的开销。

也就是再次从 S 寻找到 b 的开销。

这个过程看似复杂,但是代码实现起来很优雅,因为它的本质就是回溯!

(3)在同一次 DFS 中。如果从一个点引发不出任何的增广路径,就将这个点在层次图中抹去。

poj1273 链接:http://poj.org/problem?id=1273

Description

Every time it rains on Farmer John‘s fields, a pond forms over Bessie‘s favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage ditches so that Bessie‘s
clover patch is never covered in water. Instead, the water is drained to a nearby stream. Being an ace engineer, Farmer John has also installed regulators at the beginning of each ditch, so he can control at what rate water flows into that ditch.

Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network.

Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle.

Input

The input includes several cases. For each case, the first line contains two space-separated integers, N (0 <= N <= 200) and M (2 <= M <= 200). N is the number of ditches that Farmer John has dug. M is the number of intersections points
for those ditches. Intersection 1 is the pond. Intersection point M is the stream. Each of the following N lines contains three integers, Si, Ei, and Ci. Si and Ei (1 <= Si, Ei <= M) designate the intersections between which this ditch flows. Water will flow
through this ditch from Si to Ei. Ci (0 <= Ci <= 10,000,000) is the maximum rate at which water will flow through the ditch.

Output

For each case, output a single integer, the maximum rate at which water may emptied from the pond.

Sample Input

5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10

Sample Output

50
#include"stdio.h"
#include"string.h"
#define N 605
#define min(a,b) (a<b?a:b)
const int inf=0x7fffffff;
struct node
{
    int u,v,w,next;
}map[N*4];
int cnt,n,m,s,t,head[N],q[N],dis[N];
void add(int u,int v,int w)
{
    map[cnt].u=u;
    map[cnt].v=v;
    map[cnt].w=w;
    map[cnt].next=head[u];
    head[u]=cnt++;
    map[cnt].u=v;
    map[cnt].v=u;
    map[cnt].w=0;
    map[cnt].next=head[v];
    head[v]=cnt++;
}
int bfs()
{
    int i,x,v,t1,t2;
    memset(dis,0,sizeof(dis));    //节点的高度标号
    dis[s]=1;
    t1=t2=0;
    q[t2++]=s;        //模拟队列
    while(t1<t2)
    {
        x=q[t1++];
        for(i=head[x];i!=-1;i=map[i].next)
        {
            v=map[i].v;
            if(map[i].w&&!dis[v])
            {
                dis[v]=dis[x]+1;
                if(v==n)
                    return 1;
                q[t2++]=v;
            }
        }
    }
    return 0;
}
int dfs(int s,int lim)
{
    int i,v,tmp,cost=0;
    if(s==t)
        return lim;
    for(i=head[s];i!=-1;i=map[i].next)    //枚举该点连通的所有边
    {
        v=map[i].v;
        if(map[i].w&&dis[s]==dis[v]-1)
        {
            tmp=dfs(v,min(lim-cost,map[i].w));
            if(tmp>0)
            {
                map[i].w-=tmp; //利用反向边的奇偶性,增加反向边的流量
                map[i^1].w+=tmp;
                cost+=tmp;
                if(lim==cost)
                    break;
            }
            else   //在同一次 DFS 中。如果从一个点引发不出任何的增广路径,就将这个点在层次图中抹去。

                dis[v]=-1;
        }
    }
    return cost;
}
int dinic()
{
    int ans=0;
    while(bfs())
        ans+=dfs(s,inf);
    return ans;
}
int main()
{
    int u,v,w;
    while(~scanf("%d%d",&m,&n))
    {
        cnt=0;
		memset(head,-1,sizeof(head));
        while(m--)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);          //建边,反向边流量为零
        }
        s=1;t=n;
        printf("%d\n",dinic());
    }
    return 0;
}

dinic算法学习(以poj1273为例)

时间: 2024-10-11 20:49:33

dinic算法学习(以poj1273为例)的相关文章

POJ1273:Drainage Ditches(最大流入门 EK,dinic算法)

http://poj.org/problem?id=1273 Description Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer Jo

数据挖掘算法学习(三)NaiveBayes算法

算法简单介绍 NBC是应用最广的分类算法之中的一个.朴素贝叶斯模型发源于古典数学理论,有着坚实的数学基础,以及稳定的分类效率.同一时候,NBC模型所需预计的參数非常少,对缺失数据不太敏感,算法也比較简单. 算法如果 给定目标值时属性之间互相条件独立. 算法输入 训练数据   T={(x1,y1),(x2,y2),--,(xn,yn)} 待分类数据x0=(x0(1),x0(2),--,x0(n))T 算法输出 待分类数据x0的分类结果y0∈{c1,c2,--,ck} 算法思想 weka执行 以we

数据挖掘算法学习(一)K-Means算法

博主最近实习开始接触数据挖掘,将学习笔记分享给大家.目前用的软件是weka,下篇文章会着重讲解. 算法简介: K-Means算法是输入聚类个数k,以及包含n个数据对象的数据库,输出满足方差最小标准的k个聚类.并使得所获得的聚类满足:同一聚类中的对象相似度较高:而不同聚类对象相似度较小. 算法假设: 均方误差是计算群组分散度的最佳参数. 算法输入: 聚类个数k:包含n个数据对象的数据集. 算法输出: k个聚类 算法思想: (a)绿点表示数据集在二级的欧几里德空间,初始化的中心点u1和u2用红的和蓝

hiho一下 第119周 #1398 : 网络流五&#183;最大权闭合子图 【最小割-最大流--Ford-Fulkerson 与 Dinic 算法】

#1398 : 网络流五·最大权闭合子图 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 周末,小Hi和小Ho所在的班级决定举行一些班级建设活动. 根据周内的调查结果,小Hi和小Ho一共列出了N项不同的活动(编号1..N),第i项活动能够产生a[i]的活跃值. 班级一共有M名学生(编号1..M),邀请编号为i的同学来参加班级建设活动需要消耗b[i]的活跃值. 每项活动都需要某些学生在场才能够进行,若其中有任意一个学生没有被邀请,这项活动就没有办法进行. 班级建设的活

最大流 Dinic算法

Ford-Fulkerson算法是通过深度优先搜索寻找增广路,并沿着它增广. 与之相对,Dinic算法总是寻找最短的增广路,并沿着它增广.因为最短增广路的长度在增广过程中始终不会变短,所以无需每次都通过宽度预先搜索来寻找最短增广路. 我们可以先进行一次宽度优先搜索,然后考虑由进距离顶点指向远距离顶点的边所组成的分层图,在上面进行深度优先搜索寻找最短增广路. 如果在分层图上找不到新的增广路,则说明最短增长路的长度确实边长了,或不存在增广路,于是重新通过宽度优先搜索构造新的分层图.每一步构造分层图的

Python之路,Day21 - 常用算法学习

Python之路,Day21 - 常用算法学习 本节内容 算法定义 时间复杂度 空间复杂度 常用算法实例 1.算法定义 算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制.也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出.如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题.不同的算法可能用不同的时间.空间或效率来完成同样的任务.一个算法的优劣可以用空间复杂度与时间复杂度来衡量. 一个算

Geohash 算法学习

Geohash 算法: 这是一套纬度/经度地理编码算法,把纬度/经度编码成base32位的字符串.这种编码和纬度/经度不是唯一对应,其实是一个纬度/经度区间.算法有一个精度概念,精度越高,字符串越长,所表示的区间越小.可以编码后的字符串想象成一个格子,里面存放一些纬度/经度值.格子趋近很小的时候,只能存放一纬度/经度值,那么编码和纬度/经度就是唯一对应的关系.但是这个不是重点,这套算法目的就是把纬度/经度编码成近似值,通过近似值搜索,就能很高效的缩小范围,然后再从小范围里查找精确值. 例如,坐标

数据挖掘算法学习(八)Adaboost

本文不定期更新.原创文章,转载请注明出处,谢谢. Adaboost是一种迭代算法,其核心思想是针对同一个训练集训练不同的分类器(弱分类器),然后把这些弱分类器集合起来,构成一个更强的最终分类器(强分类器).Adaboost算法本身是通过改变数据分布来实现的,它根据每次训练集之中每个样本的分类是否正确,以及上次的总体分类的准确率,来确定每个样本的权值.将修改过权值的新数据集送给下层分类器进行训练,最后将每次得到的分类器最后融合起来,作为最后的决策分类器. 算法概述 1.先通过对N个训练样本的学习得

算法学习记录-查找——平衡二叉树(AVL)

排序二叉树对于我们寻找无序序列中的元素的效率有了大大的提高.查找的最差情况是树的高度.这里就有问题了,将无序数列转化为 二叉排序树的时候,树的结构是非常依赖无序序列的顺序,这样会出现极端的情况. [如图1]: 这样的一颗二叉排序树就是一颗比较极端的情况.我们在查找时候,效率依赖树的高度,所以不希望这样极端情况出现,而是希望元素比较均匀 的分布在根节点两端. 技术参考:fun4257.com/ 问题提出: 能不能有一种方法,使得我们的二叉排序树不依赖无序序列的顺序,也能使得我们得到的二叉排序树是比