[hdu 1532] Drainage Ditches(最大流dinic)
2014-04-17 14:57
405 查看
算是一个网络流入门介绍贴吧,这里就不说各种剩余图,层次图的概念了,这些网上太多了,这里直接说些实在点的东西吧。
网络:的意思是给定一个网络(有向图),这个网络中有起点也有终点,各条边上的流量表示最大值,也就是有多少单位的东西能够经过这条边。
最大流是网络流的其中一类问题,求的是从起点出发,最终有多少个"货物"能到达终点。以一个图来理解一下这个最大流:
这个图的答案应该是9,1->2->4->5能运送4个货物,1->3->5能运送5个货物,所以到了终点一共是9个货物。有必要补充几点:
1.一条路上能运送的最大数量取决去这条路上运送能力最弱的路段,即数值最小的边。这句话对稍后的编程非常重要。
2.起点运送到终点,所以可以看成起点是仓库(起点能运出来无穷多的货物),终点也是仓库(起点能够运的过来多少东西,终点就能接收多少东西),唯一受限制的就是每个路段的运送能力了。
回到这个题目,首先先将题目抽象:
告诉有n条边,共m个点(1~m),然后是n条边的头尾与流量。1是起点,m是终点,问能运达终点的最大流量是多少。
这里简要介绍一下dinic算法:
1.用bfs对各顶点标号,计算出层次图,如果层次图中没有出现终点,那么说明最大流计算完毕。
层次图的计算方法为:设一个dep数组表示各结点的层次(可以理解成从起点出发的深度)。从已访问过的结点出发,如果从这个点出去的没访问的边的流量大于零,那么这条边的终点那个结点的层次为起点的层次+1.
2.用dfs找出一条通往终点的可行的路,这条路称为增广路,设这条路上流量最小值为x,那么整条路每个路段流量减去x,答案加上x。
分析一下这道题的样例数据,首先构图(起点和终点用绿色以示突出):
第一步是构建层次图(红色为层次):
dfs寻找增广路,找到了:
目前为止知道至少有20的流量能到终点了,然后在原图中减掉这条路的流量,为了方便,如果哪条路流量为0就不再画出。
继续建立层次图:
找增广路:
目前为止已有20+现在的20=40的流量能到终点了,继续更新原图。
建立层次图以及寻找增广路:
20+20+10 = 50
现在的图:
增广完毕,答案为50.
其实还有个反向边的概念,上图的数据中因为没用到所以没有画出来,不过这是不可忽略的。本文已十分冗长,只是起个抛砖引玉的作用,关于反向边的概念请另行搜索网络流神牛们的文章。
附上完整程序:
网络:的意思是给定一个网络(有向图),这个网络中有起点也有终点,各条边上的流量表示最大值,也就是有多少单位的东西能够经过这条边。
最大流是网络流的其中一类问题,求的是从起点出发,最终有多少个"货物"能到达终点。以一个图来理解一下这个最大流:
这个图的答案应该是9,1->2->4->5能运送4个货物,1->3->5能运送5个货物,所以到了终点一共是9个货物。有必要补充几点:
1.一条路上能运送的最大数量取决去这条路上运送能力最弱的路段,即数值最小的边。这句话对稍后的编程非常重要。
2.起点运送到终点,所以可以看成起点是仓库(起点能运出来无穷多的货物),终点也是仓库(起点能够运的过来多少东西,终点就能接收多少东西),唯一受限制的就是每个路段的运送能力了。
回到这个题目,首先先将题目抽象:
告诉有n条边,共m个点(1~m),然后是n条边的头尾与流量。1是起点,m是终点,问能运达终点的最大流量是多少。
这里简要介绍一下dinic算法:
1.用bfs对各顶点标号,计算出层次图,如果层次图中没有出现终点,那么说明最大流计算完毕。
层次图的计算方法为:设一个dep数组表示各结点的层次(可以理解成从起点出发的深度)。从已访问过的结点出发,如果从这个点出去的没访问的边的流量大于零,那么这条边的终点那个结点的层次为起点的层次+1.
int bfs() // 建立层次图 { queue<int> q; memset(dep, -1, sizeof(dep)); // 初始化结点的层次 dep[st] = 0; // 从起点开始,起点层次为0(深度0) q.push(st); while(!q.empty()) { int cur = q.front(); q.pop(); for(int i = head[cur]; i != -1; i = edge[i].next) { int s = edge[i].t; if(dep[s] == -1 && edge[i].flow > 0) // 未访问过, 且这条边的流量大于零 { dep[s] = dep[cur] + 1; q.push(s); } } } // 若终点不在层次图中, 说明bfs的时候没访问到终点 // 也就是说通向终点的边的流量都变成0了 return dep[end] != -1; }
2.用dfs找出一条通往终点的可行的路,这条路称为增广路,设这条路上流量最小值为x,那么整条路每个路段流量减去x,答案加上x。
int dfs(int st, int limit) // 起点和限制流量(从起点到当前的边的最小流量) { int x; if(st == end) // 当走到终点时,一路下来的最小值就是答案, 所以返回limit return limit; for(int i = head[st]; i != -1; i = edge[i].next) { int s = edge[i].t; if(edge[i].flow > 0 && dep[s] == dep[st] + 1) // 一路过来, 层次逐渐加深 { x = dfs(s, min(limit, edge[i].flow)); if(x == 0)continue; // 这条路不通, 找下一条路 edge[i].flow -= x; return x; } } return 0; }3.转步骤2继续构建层次图和寻找增广路,直到增广完毕。
分析一下这道题的样例数据,首先构图(起点和终点用绿色以示突出):
第一步是构建层次图(红色为层次):
dfs寻找增广路,找到了:
目前为止知道至少有20的流量能到终点了,然后在原图中减掉这条路的流量,为了方便,如果哪条路流量为0就不再画出。
继续建立层次图:
找增广路:
目前为止已有20+现在的20=40的流量能到终点了,继续更新原图。
建立层次图以及寻找增广路:
20+20+10 = 50
现在的图:
增广完毕,答案为50.
其实还有个反向边的概念,上图的数据中因为没用到所以没有画出来,不过这是不可忽略的。本文已十分冗长,只是起个抛砖引玉的作用,关于反向边的概念请另行搜索网络流神牛们的文章。
附上完整程序:
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
#define maxn 210
#define inf 0x3f3f3f3
struct Edge
{
int t;
int flow;
int next;
}edge[maxn * 3];
int head[maxn];
int dep[maxn];
int n, m;
int st, end;
int edgenum;
int min(int a, int b)
{
return a < b ? a : b;
}
void addedge(int s, int t, int flow)
{
edge[edgenum].t = t;
edge[edgenum].flow = flow;
edge[edgenum].next = head[s];
head[s] = edgenum++;
}
int bfs() // 建立层次图 { queue<int> q; memset(dep, -1, sizeof(dep)); // 初始化结点的层次 dep[st] = 0; // 从起点开始,起点层次为0(深度0) q.push(st); while(!q.empty()) { int cur = q.front(); q.pop(); for(int i = head[cur]; i != -1; i = edge[i].next) { int s = edge[i].t; if(dep[s] == -1 && edge[i].flow > 0) // 未访问过, 且这条边的流量大于零 { dep[s] = dep[cur] + 1; q.push(s); } } } // 若终点不在层次图中, 说明bfs的时候没访问到终点 // 也就是说通向终点的边的流量都变成0了 return dep[end] != -1; }
int dfs(int st, int limit) // 起点和限制流量(从起点到当前的边的最小流量)
{
int x;
if(st == end) // 当走到终点时,一路下来的最小值就是答案, 所以返回limit
return limit;
for(int i = head[st]; i != -1; i = edge[i].next)
{
int s = edge[i].t;
if(edge[i].flow > 0 && dep[s] == dep[st] + 1) // 一路过来, 层次逐渐加深
{
x = dfs(s, min(limit, edge[i].flow));
if(x == 0)continue; // 这条路不通, 找下一条路
edge[i].flow -= x;
edge[i^1].flow += x;
return x;
}
}
return 0;
}
int dinic()
{
int flow = 0, t;
while(bfs())
{
flow += dfs(st, inf);
}
return flow;
}
int main()
{
int a, b, c;
while(~scanf("%d%d", &n, &m))
{
edgenum = 0;
memset(head, -1, sizeof(head));
for(int i = 0; i < n; i++)
{
scanf("%d%d%d", &a, &b, &c);
addedge(a, b, c);
addedge(b, a, 0);
}
st = 1, end = m;
int re = dinic();
printf("%d\n", re);
}
return 0;
}
相关文章推荐
- hdu - 1532 Drainage Ditches (最大流)
- HDU_1532 && HDU_3549(最大流EK算法模板)
- HDU 1532 Drainage Ditches(最大流+EK算法模板题)
- HDU 1532 Drainage Ditches 最大网络流
- hdu 1532 最大流
- HDU-1532(网络最大流)
- hdu 1532 Drainage Ditches (最大流)
- hdu 1532 Drainage Ditches 最大流 dinic算法
- poj 1273 hdu 1532 Drainage Ditches 最大流dinic 算法
- poj 1273 & hdu 1532 Drainage Ditches(最大流 )EK,dinic模板
- HDU 1532 Drainage Ditches 最大流
- HDU 1532 Drainage Ditches【E-K 最大流】
- poj 1273 || hdu 1532 Drainage Ditches 最大流
- HDU 1532 Drainage Ditches(最大流)
- HDU--杭电--1532--Drainage Ditches--最大流
- hdu 1532 最大流水题
- hdu 1532 Drainage Ditches 最大流 dinic算法
- POJ 1273,HDU 1532 Drainage Ditches(最大流)
- 【最大流 模板题 EdmondsKarp】HDU - 1532 Drainage Ditches
- hdu1532--Drainage Ditches(最大流(EK算法))