网络流的基本概念跟算法原理我是在以下两篇博客里看懂的,写的非常好。

http://www.cnblogs.com/ZJUT-jiangnan/p/3632525.html

http://www.cnblogs.com/zsboy/archive/2013/01/27/2878810.html

网络流有四种算法, 包括 Edmond-Karp(简称EK), Ford-Fulkerson(简称FF), dinic算法以及SAP算法。

下面我会写出前三种算法的矩阵跟邻接表的形式, 对于第四种以后有必要再补充上, 其中dinic算法是比较高效的算法, 要重点掌握dinc,其他两种我是当做辅助理解网络流的,以后做题还是得练dinic

领接矩阵:适用于稠密图,原因:矩阵大小是 n * n的,若边m << n * n,则矩阵中有很多空位置,造成空间浪费, 所以只有稠密图才适合矩阵写法

邻接表:适用于稀疏图,原因:附加链域,稠密图不适合

附上例题链接:http://poj.org/problem?id=1273

1.Edmond-Karp

邻接矩阵:

 //邻接矩阵 

 #include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#define mem(a, b) memset(a, b, sizeof(a))
const int inf = 0x3f3f3f3f;
using namespace std; int m, n;//m为边的数量, n为点的数量
int map[][];//存图
int flow[]; //记录bfs查找时的最小边,类似木桶效应
int pre[];
queue<int>Q; int bfs(int st, int ed)
{
while(!Q.empty())//队列清空
Q.pop();
for(int i = ; i <= n; i ++)//1.点的前驱, 利用前驱来更新路径上的正反向边的所剩容量 2.标记是否已经遍历过
pre[i] = -;
flow[st] = inf;//flow数组只需要每次bfs时将源点初始化为inf即可, 不需要全部初始化,因为更新时只跟上一个状态以及map边的信息有关
Q.push(st);
while(!Q.empty())
{
int index = Q.front();
Q.pop();
if(index == ed)//找到一条增广路径
break;
for(int i = ; i <= n; i ++)//遍历图
{
if(pre[i] == - && map[index][i] > && i != st)//1.没经过i点 2.边的容量大于0 3.终点不为起点,防止没经过汇点死循环
{
flow[i] = min(flow[index], map[index][i]);//找到一个可行流上最小的一条边
pre[i] = index;//记录前驱
Q.push(i);
}
}
}
if(pre[ed] == -)//汇点前驱没被更新说明没找到增广路径
return -;
else
return flow[ed];
} int max_flow(int st, int ed)
{
int inc; //每次bfs查找得到的增量
int ans = ; //记每次的增量之和为答案
while((inc = bfs(st, ed)) != -)
{
int k = ed; //从汇点往回更新
while(k != st)
{
int last = pre[k];
map[last][k] -= inc;
map[k][last] += inc;
k = last;
}
ans += inc;
}
return ans;
} int main()
{
while(scanf("%d%d", &m, &n)!=EOF)
{
mem(map, );//图的边容量初始化为0
for(int i = ; i <= m; i ++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
if(a == b)
continue;
map[a][b] += c;//网络流单向边,若i到j有多根管子,可看作容量叠加的一根管子
}
int ans = max_flow(, n); //源点1到汇点n的最大流
printf("%d\n", ans);
}
return ;
}

邻接表(链式前向星实现)

 //链式前向星 

 #include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#define mem(a, b) memset(a, b, sizeof(a))
const int inf = 0x3f3f3f3f;
using namespace std; struct Edge
{
int next, to, val;
}edge[ * ];//反向边 开两倍空间 int m, n;
int head[], cnt, pos[];
int flow[];
int pre[];
queue<int>Q; void add(int a, int b, int c)
{
edge[cnt].to = b;
edge[cnt].val = c;
edge[cnt].next = head[a];
head[a] = cnt ++; edge[cnt].to = a;
edge[cnt].val = ;//反向边容量初始化为0
edge[cnt].next = head[b];
head[b] = cnt ++;
} int bfs(int st, int ed)
{
mem(pos, -);
while(!Q.empty())
Q.pop();
for(int i = ; i <= n; i ++)
pre[i] = -;
flow[st] = inf;
Q.push(st);
while(!Q.empty())
{
int a = Q.front();
Q.pop();
if(a == ed)
return flow[ed];
for(int i = head[a]; i != -; i = edge[i].next)
{
int to = edge[i].to;
if(pre[to] == - && edge[i].val > && to != st)
{
flow[to] = min(flow[a], edge[i].val);
pre[to] = a;
pos[to] = i;//储存寻找到的路径各边的位置, 用于更新val时参与 ^ 运算
Q.push(to);
}
}
}
return -;
} int max_flow(int st, int ed)
{
int inc;
int ans = ;
while((inc = bfs(st, ed)) != -)
{
int k = ed;
while(k != st)
{
edge[pos[k]].val -= inc;//巧用 ^1 运算, 0 ^ 1 = 1, 1 ^1 = 0, 2 ^ 1 = 3, 3 ^ 1 = 2, 4 ^ 1 = 5, 5 ^ 1 = 4.
// 所以这里链式前向星必须从0开始存边, 这样的话刚好正反向边与 ^ 运算一一对应,例如找到2边, 那么更新2, 3边, 找到3边,那么更新2, 3边
edge[pos[k] ^ ].val += inc;
k = pre[k];
}
ans += inc;
}
return ans;
} int main()
{
while(scanf("%d%d", &m, &n)!=EOF)
{
cnt = ;
mem(head, -);
for(int i = ; i <= m; i ++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
if(a == b)
continue;
add(a, b, c);//链式前向星存储的是边的位置, 不需要特别处理重边, 存了的边都会在寻找增广路中被用到
}
int ans = max_flow(, n);
printf("%d\n", ans);
}
return ;
}

 2.Ford-Fulkerson

这个算法不常用, 可以用于理解后面的dinic算法, 不是很重要,在同学博客里复制过来,嘿嘿嘿

邻接矩阵

 #include<iostream>
#include<string.h>
#include<queue>
using namespace std; int map[][];
int n,m;
bool vis[];//标记该点有没有用过 int dfs(int start,int ed,int cnt)
{ //cnt是查找到的增广路中流量最小的边
if(start == ed)
return cnt; //起点等于终点,即已经查到一条可行增广路
for(int i = ; i <= m; i ++)
{ //以起点start遍历与它相连的每一条边
if(map[start][i] > && !vis[i])
{ //这条边是否可行
vis[i] = true; //标记已经走过
int flow = dfs(i, ed, min(cnt, map[start][i]));//递归查找
if(flow > )
{ //回溯时更行map,这和EK的迭代更行差不多
map[start][i] -= flow;
map[i][start] += flow;
return flow;
}
}
}
return ;//没找到
}
int Max_flow(int start, int ed)
{
int ans = ;
while(true)
{
memset(vis, false, sizeof(vis));
int inc = dfs(start, ed, 0x3f3f3f3f);//查找增广路
if(inc == )
return ans;//没有增广路了
ans+=inc;
}
}
int main()
{
int start, ed, w;
while(cin >> n >> m)
{
memset(map, , sizeof(map));
for(int i = ; i < n; i ++)
{
cin >> start >> ed >> w;
if(start == ed)
continue;
map[start][ed] += w;
}
cout<<Max_flow(,m)<<endl;
}
return ;
}

邻接表:

不写了, 这个算法不重要 

3.dinic

这个算法是要求掌握。这是求解网络流较高效速度比较快的方法。

算法思想:

在寻找增广路之前进行bfs对边进行分层, 例如有边, 1->2,1->3,2->4, 3->4,2->3.那么分层之后就是第一层为点1,第二层为点2, 3.第三层为点4。然后在寻找增广路径时通过层次访问, 就避免了2->3这条边的访问。提高了效率。

邻接矩阵:

 #include<stdio.h>
#include<queue>
#include<string.h>
#include<algorithm>
#define mem(a, b) memset(a, b, sizeof(a))
const int inf = 0x3f3f3f3f;
using namespace std; int m, n;
int map[][];
int dep[];//点所属的层次
queue<int>Q; int bfs(int st, int ed)
{
if(st == ed)
return ;
while(!Q.empty())
Q.pop();
mem(dep, -); //层次初始化
dep[st] = ; //起点定义为第一层
Q.push(st);
while(!Q.empty())
{
int index = Q.front();
Q.pop();
for(int i = ; i <= n; i ++)
{
if(map[index][i] > && dep[i] == -)
{
dep[i] = dep[index] + ;
Q.push(i);
}
}
}
return dep[ed] != -;//返回是否能成功分层,若无法分层说明找不到增广路径了,
} int dfs(int now, int ed, int cnt)
{
if(now == ed)//跳出条件, 找到了汇点,获得一条增广路径
return cnt;
for(int i = ; i <= n; i ++)
{
if(dep[i] == dep[now] + && map[now][i] > )
{
int flow = dfs(i, ed, min(cnt, map[now][i]));
if(flow > )//这条增广路径上最小的边的flow值来更新整个路径
{
map[now][i] -= flow;
map[i][now] += flow;
return flow;
}
}
}
return -;//该种分层已经无法找到增广路径
} int max_flow(int st, int ed)
{
int ans = ;
while(bfs(st, ed))
{
while()
{
int inc = dfs(st, ed, inf);
if(inc == -)
break;
ans += inc;
}
}
return ans;
} int main()
{
while(scanf("%d%d", &m, &n)!=EOF)
{
mem(map, );
for(int i = ; i <= m; i ++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
if(a == b)
continue;
map[a][b] += c;
}
printf("%d\n", max_flow(, n));
}
return ;
}

邻接表(链式前向星实现):

 #include<stdio.h>
#include<queue>
#include<string.h>
#include<algorithm>
#define mem(a, b) memset(a, b, sizeof(a))
const int inf = 0x3f3f3f3f;
using namespace std; int m, n;
int head[], cnt;
int dep[];
queue<int>Q; struct Edge
{
int to, next, val;
}edge[]; void add(int a, int b, int c)// ^ 运算, 从0开始存边
{
edge[cnt].to = b;
edge[cnt].val = c;
edge[cnt].next = head[a];
head[a] = cnt ++; edge[cnt].to = a;
edge[cnt].val = ;//反向边容量初始化 0
edge[cnt].next = head[b];
head[b] = cnt ++;
} int bfs(int st, int ed)
{
if(st == ed)
return ;
while(!Q.empty())
Q.pop();
mem(dep, -);//层次初始化
dep[st] = ; //第一层定义为 1
Q.push(st);
while(!Q.empty())
{
int index = Q.front();
Q.pop();
for(int i = head[index]; i != -; i = edge[i].next)
{
int to = edge[i].to;
if(edge[i].val > && dep[to] == -)
{
dep[to] = dep[index] + ;
Q.push(to);
}
}
}
return dep[ed] != -;
} int dfs(int now, int ed, int cnt)
{
if(now == ed)
return cnt;
for(int i = head[now]; i != -; i = edge[i].next)
{
int to = edge[i].to;
if(dep[to] == dep[now] + && edge[i].val > )
{
int flow = dfs(to, ed, min(cnt, edge[i].val));
if(flow > )
{
edge[i].val -= flow;
edge[i ^ ].val += flow;
return flow;
}
}
}
return -;
} int max_flow(int st, int ed)
{
int ans = ;
while(bfs(st, ed))
{
while()
{
int inc = dfs(st, ed, inf);
if(inc == -)
break;
ans += inc;
}
}
return ans;
} int main()
{
while(scanf("%d%d", &m, &n)!=EOF)
{
cnt = ;
mem(head, -);
for(int i = ; i <= m; i ++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
if(a == b)
continue;
add(a, b, c);
}
printf("%d\n", max_flow(, n));
}
return ;
}

  

网络流三大算法【邻接矩阵+邻接表】POJ1273的更多相关文章

  1. 数据结构学习笔记05图 (邻接矩阵 邻接表-->BFS DFS、最短路径)

    数据结构之图 图(Graph) 包含 一组顶点:通常用V (Vertex) 表示顶点集合 一组边:通常用E (Edge) 表示边的集合 边是顶点对:(v, w) ∈E ,其中v, w ∈ V 有向边& ...

  2. hdu 1874 畅通工程(spfa 邻接矩阵 邻接表)

    题目链接 畅通工程,可以用dijkstra算法实现. 听说spfa很好用,来水一发 邻接矩阵实现: #include <stdio.h> #include <algorithm> ...

  3. 第6章 图的学习总结(邻接矩阵&邻接表)

    我觉得图这一章的学习内容更有难度,其实图可以说是树结构更为普通的表现形式,它的每个元素都可以与多个元素之间相关联,所以结构比树更复杂,然而越复杂的数据结构在现实中用途就越大了,功能与用途密切联系,所以 ...

  4. POJ 3013 SPFA算法,邻接表的使用

    Big Christmas Tree Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 19029   Accepted: 4 ...

  5. 图的全部实现(邻接矩阵 邻接表 BFS DFS 最小生成树 最短路径等)

    1 /** 2 * C: Dijkstra算法获取最短路径(邻接矩阵) 3 * 6 */ 7 8 #include <stdio.h> 9 #include <stdlib.h> ...

  6. HDU 1874 畅通工程续(最短路/spfa Dijkstra 邻接矩阵+邻接表)

    题目链接: 传送门 畅通工程续 Time Limit: 1000MS     Memory Limit: 65536K Description 某省自从实行了很多年的畅通工程计划后,终于修建了很多路. ...

  7. <图论入门>邻接矩阵+邻接表

    非本人允许请勿转载. 趁热打铁,学会了邻接表把这个总结一下,以及感谢大佬uncle-lu!!!(奶一波)祝早日进队! 首先,图论入门就得是非常基础的东西,先考虑怎么把这个图读进去. 给定一个无向图,如 ...

  8. 最短路径SPFA算法(邻接表存法)

    queue <int> Q; void SPFA (int s) { int i, v; for(int i=0; i<=n; i++) dist[i]=INF; //初始化每点i到 ...

  9. c语言实现迪杰斯特拉算法(邻接表)

    储存结构,结构体的定义:(权值w用于表示两点间路径的花费) typedef int Status; typedef struct ENode//图的邻接表定义 { int adjVex;//任意顶点u ...

随机推荐

  1. crypot.js 生成hash256, 在IE下的卡顿问题。

    项目需求: 上传大文件,调用crypto.js生成hash256码. 直接上传大文件,IE会直接崩溃. 于是利用file.slice分片检测.但是浏览器会出现卡顿问题.开始以为是内存泄漏.但看服务器进 ...

  2. WebUI自动化之Java语言讲解

    Java学习网站:  default是兜底逻辑,以上条件都不符合时,如何处理.  break是终止循环,continue是终止本次循环:

  3. BZOJ 1706: [usaco2007 Nov]relays 奶牛接力跑 倍增Floyd

    题不难,但是一开始把读入看错了,调了半天qaq~ Code: #include <bits/stdc++.h> #define N 300 #define setIO(s) freopen ...

  4. [Cogs] 最大数maxnumber

    http://cogs.pro:8080/cogs/problem/problem.php?pid=1844 Luogu 的数据真zhizhang Cogs AC #include <iostr ...

  5. 【maven】【spring boot】【单元测试】 使用controller 执行单元测试类

    存在这样一个场景: 当项目启动时间过长,又没办法缩短的时候,写单元测试就是一个十分耗时的工作, 这工作不在于使用编写代码,而在于每次run junit test 都需要完整启动一次项目,白白浪费宝贵的 ...

  6. iOS 8 - Can't Install Enterprise App

    http://stackoverflow.com/questions/25733299/ios-8-cant-install-enterprise-app 版权声明:本文为博主原创文章,未经博主允许不 ...

  7. Could not initialize class sun.awt.X11GraphicsEnvironment异常处理

    原因导致: 经过Google发现很多人也出现同样的问题.从了解了X11GraphicEnvironment这个类的功能入手, 一个Java服务器来处理图片的API基本上是需要运行一个X-server以 ...

  8. 安装wget 、 wget命令

    今天给服务器安装新LNMP环境时,wget 时提示 -bash:wget command not found,很明显没有安装wget软件包.一般linux最小化安装时,wget不会默认被安装. 可以通 ...

  9. css实现元素在div底部显示

    #CSS .1 {position:relative;} .2 {;} #HTML <div class="1"> <div class="2" ...

  10. POJ 1135 -- Domino Effect(单源最短路径)

     POJ 1135 -- Domino Effect(单源最短路径) 题目描述: 你知道多米诺骨牌除了用来玩多米诺骨牌游戏外,还有其他用途吗?多米诺骨牌游戏:取一 些多米诺骨牌,竖着排成连续的一行,两 ...