最大流
最大流的最原型题目是给定一个网络,问你从源点最多一次能流多少流到汇点。
这样说有点不懂,我打个比方:给定一个电路图,有以下几个特征:
1.每条导线 (i) 有个每秒最大电流通过值 (Ci) (你可以理解为过了这个值导线就烧了所以这条导线上的最大电流不能超过这个值)
2.对于串联的电路,若a与b串联,那么这条串联路每秒可通过的最大电流为((min(Ca,Cb)))
3.对于并联的电路,若a与b并联,那么通过这条等价并联电路的最大电流为((Ca + Cb))
4.电流速度为(INF)
5.求导线联通(1S)能到汇点的最大电流
如下题所示:
P1343 地震逃生
题目描述
汶川地震发生时,四川**中学正在上课,一看地震发生,老师们立刻带领x名学生逃跑,整个学校可以抽象地看成一个有向图,图中有n个点,m条边。1号点为教室,n号点为安全地带,每条边都只能容纳一定量的学生,超过楼就要倒塌,由于人数太多,校长决定让同学们分成几批逃生,只有第一批学生全部逃生完毕后,第二批学生才能从1号点出发逃生,现在请你帮校长算算,每批最多能运出多少个学生,x名学生分几批才能运完。
输入输出格式
输入格式:
第一行3个整数n,m,x(x<2^31,n<=200,m<=2000);以下m行,每行三个整数a,b,c(a1,a<>b,0描述一条边,分别代表从a点到b点有一条边,且可容纳c名学生。
输出格式:
两个整数,分别表示每批最多能运出多少个学生,x名学生分几批才能运完。如果无法到达目的地(n号点)则输出“Orz Ni Jinan Saint Cow!”
最大流的板题,我们采用Dinic算法(当前弧优化版本):
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int RD(){
int out = 0,flag = 1;char c = getchar();
while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
return flag * out;
}
const int maxn = 100019,INF = 1e9;;
int num,nr,nume;
int tot;
int s,t,maxflow;
int head[maxn],cur[maxn];//cur为当前弧优化
struct Node{
int v,dis,nxt;
}E[maxn << 2];
void add(int u,int v,int dis){
E[++nume].nxt = head[u];
E[nume].v = v;
E[nume].dis = dis;
head[u] = nume;
}
int d[maxn];
bool bfs(){
queue<int>Q;
memset(d,0,sizeof(d));
for(int i = 1;i <= t;i++)cur[i] = head[i];//当前弧优化
Q.push(s);
d[s] = 1;
while(!Q.empty()){
int u = Q.front();
Q.pop();
for(int i = head[u];i;i = E[i].nxt){
int v = E[i].v;
if(E[i].dis && !d[v]){
d[v] = d[u] + 1;
Q.push(v);
if(v == t)return 1;
}
}
}
return 0;
}
int Dinic(int u,int flow){
if(u == t)return flow;
int rest = flow,k;
for(int i = cur[u];i != -1;i = E[i].nxt){
cur[u] = i;
int v = E[i].v;
if(E[i].dis && d[v] == d[u] + 1){
k = Dinic(v,min(rest,E[i].dis));
if(!k)d[v] = 0;//玄学剪枝
E[i].dis -= k;
E[i ^ 1].dis += k;
rest -= k;
}
if(rest == 0)break;//配合当前弧优化
}
return flow - rest;
}
int main(){
memset(head,-1,sizeof(head));//如果head开始是-1,记得初始化
num = RD();nr = RD();s = 1;t = num;
tot = RD();
int u,v,c;
nume = 1;
for(int i = 1;i <= nr;i++){
u = RD();v = RD();c = RD();
add(u,v,c);
add(v,u,0);
}
int flow = 0;
while(bfs()){
while(flow = Dinic(s,INF))maxflow += flow;//在每个分层图中跑Dinic
}
if(maxflow == 0){
printf("Orz Ni Jinan Saint Cow!
");//到不了汇点,大家都得死
return 0;
}
printf("%d ",maxflow);
if(tot % maxflow == 0){
printf("%d
",tot / maxflow);
return 0;
}
printf("%d
",tot / maxflow + 1);
return 0;
}
总结
网络流类题目主要考察的并不是算法的运用,而是对构建模型的理解,对此,在后续的博客中会一一讲解。