对于网络流的解释可以看一下这位大佬的博客
链接
题目链接在这里鸭
题目链接
题意:
现在教学楼里发生火灾,需要安排同学撤离,现在给出逃生的各个通道,每个通道都有一个最大容量,现在校长需要安排学生们分批撤离,每批同学都是同时从1号点出发,同时到达n号点,现在问你每批学生最多是多少人,最少多少批撤完
分析:
这个题目就是很明显的网络流的最大流,网络流的关键思想就是建立反向边给程序一个反悔的机会,可以采用dfs的思路来解决这道题,dfs的参数是当前节点和当前能承受的最大容量,即最大残量,在这个地方说残量应该是比较的精准,因为可能不止一条路从这条边经过,所以说可能某一条路刚过来的时候他已经分配了一些流量给某条路了,下面请看代码吧:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<list>
#include<unordered_map>
#define lowbit(x) (x&-x)
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
typedef unsigned long long ull;
const int inf = 0x3f3f3f3f;
const int N = 20010;
int h[N],e[N],w[N],ne[N],idx;
void add(int a,int b,int c){链式前向星建图
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
int dis[N/10];、、深度
int n,m,x;
bool bfs(){//广搜求深度,如果最后一个点没有被走到的话它的深度记为-1,这
//时候需要结束循环了
memset(dis,-1,sizeof dis);//这个很关键,因为每一次的bfs都是不一样的
dis[1] = 0;
queue<int> q;
q.push(1);
while(!q.empty()){
int t = q.front();
q.pop();
for(int i=h[t];i!=-1;i=ne[i]){
int j = e[i];
if(dis[j] == -1 && w[i] != 0){//这条边还有残量
dis[j] = dis[t] + 1;
q.push(j);
}
}
}
return dis[n] != -1;
}
int dfs(int u,int flo){
if(u == n) return flo;
int delta = flo;//delta记录的是在这个点经过了多少流量,最后求答案的
//时候要用传来的最大流量减去还剩的流量
for(int i=h[u];i!=-1;i=ne[i]){
int j = e[i];
if(dis[j] == dis[u]+1 && w[i] > 0){
int d = dfs(j,min(delta,w[i]));
w[i] -= d;
w[i^1] += d;//i的反向边
delta -= d;
if(delta == 0) break;//这时候已经满载了
}
}
return flo - delta;
}
int main(){
scanf("%d%d%d",&n,&m,&x);
memset(h,-1,sizeof h);
for(int i=1;i<=m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,0);//建立反向边
}
int ans = 0;
while(bfs()){
ans += dfs(1,inf);//初始值给他来个无穷大,后来的时候不会受到影响
}
if(ans == 0) puts("Orz Ni Jinan Saint Cow!");
else cout<<ans<<" "<<x/ans+(x%ans!=0)<<endl;
return 0;
}