题目描述
航哥是个土豪,他想在让城市布满他的婚车。但是城市的每条道路单位时间能通过的婚车是有限的,超出则会造成拥堵。他在1号点屯了足够数量的车子,他想知道从城市1号点派出婚车去n号点迎接新娘,在买通交警只允许他的婚车在车道上行驶的条件下,足够多时间之后,n号点单位时间内最多能容纳多少量婚车。
输入
第一行两个整数,n和m,n为点数,m为边数,点的标号为1~n。
接下来M行,每行三个整数a, b, c, 表示城市中两个点之间有一条单位时间最多通行c辆车的道路。
建图连边之前请注意审题……
1≤n≤10001≤n≤1000
1≤m≤1000001≤m≤100000
1≤a,b≤n,a≠b1≤a,b≤n,a≠b
1≤c≤101≤c≤10
输出
输出一个整数,点n处单位时间内最多接受的婚车数量。
输入样例
4 6
1 2 5
1 3 2
1 4 3
2 3 3
2 4 3
3 4 10
输出样例
10
http://blog.sina.com.cn/s/blog_6cf509db0100uy5n.html
最大流模板题,需要注意的是路是双向的,r[a][b]=c,r[b][a]=c;
用EK算法实现,邻接矩阵存储图。
找增广路的过程:
bfs本身是用作遍历图的算法,但在遍历的同时会生成一条从起点至某一点的路径(且该路径始终是当前图中从起点到该点的最短路径,EK利用这一特点可以按一定顺序寻找增光路)
那么如何在bfs遍历过程中找到这条路径呢?考虑bfs的详细过程,是一层一层辐射状散开寻找点的,且到达每一个点之前的前一个点都是唯一的,因此可以用一维数组pre存储这个路径(前驱),pre[i]=p表示路径上点i的前一个点为p,每次只要遍历到汇点t就结束bfs(可能此时bfs并未遍历完,但后边的结果我们都不需要了)。至此就找到一条增广路。
之后我们再拿着找到的增广路对残余网络进行更新,再去寻找新的增广路直到找不到增广路为止。
(另外注意用队列实现bfs时,push后就要马上把visit置1,否则会由重复元素进入队列)
ac代码
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 8 const int maxn=1007; 9 const int inf=0x7fffffff; 10 11 int r[maxn][maxn]; 12 bool visit[maxn]; 13 int pre[maxn]; 14 int m,n; 15 //bfs寻找增光路,找到返回ture 16 bool bfs(int s,int t){ 17 queue<int> q; 18 int p; 19 memset(visit,false,sizeof(visit)); 20 memset(pre,-1,sizeof(pre)); 21 pre[s]=s; 22 q.push(s); 23 visit[s]=true; 24 while(!q.empty()){ 25 p=q.front(); 26 q.pop(); 27 //认为节点的数组下标从1开始,用邻接矩阵存储 28 for(int i=1;i<=n;++i){ 29 if(r[p][i]>0&&!visit[i]){ 30 visit[i]=true; 31 pre[i]=p; 32 if(i==t) 33 return true; 34 q.push(i); 35 } 36 } 37 } 38 return false; 39 } 40 int EK(int s,int t){ 41 //inc表示增广路可增加的流量 42 int maxflow=0,inc; 43 while(bfs(s,t)){ 44 //坑:每次循环一开始都要置inc为inf 45 inc=inf; 46 for(int i=t;i!=s;i=pre[i]){ 47 if(inc>r[pre[i]][i]){ 48 inc=r[pre[i]][i]; 49 } 50 } 51 //这里要求如果两点之间没有边时权重r初始化为0 52 for(int i=t;i!=s;i=pre[i]){ 53 54 r[pre[i]][i]-=inc; 55 r[i][pre[i]]+=inc; 56 } 57 maxflow+=inc; 58 } 59 return maxflow; 60 } 61 void startEK(){ 62 int a,b,c; 63 int ans; 64 65 //while(~scanf("%d%d",&n,&m)){ 66 scanf("%d%d",&n,&m); 67 memset(r,0,sizeof(r)); 68 for(int i=0;i<m;++i){ 69 scanf("%d%d%d",&a,&b,&c); 70 r[a][b]+=c; 71 //看是否为双向路 72 r[b][a]=c; 73 } 74 //默认s=1,t=n 75 ans=EK(1,n); 76 printf("%d ",ans); 77 //} 78 return; 79 } 80 int main() 81 { 82 startEK(); 83 }
最大流模板(邻接矩阵)
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 8 const int maxn=1007; 9 const int inf=0x7fffffff; 10 11 int r[maxn][maxn]; 12 bool visit[maxn]; 13 int pre[maxn]; 14 int m,n; 15 //bfs寻找增光路,找到返回ture 16 bool bfs(int s,int t){ 17 queue<int> q; 18 int p; 19 memset(visit,false,sizeof(visit)); 20 memset(pre,-1,sizeof(pre)); 21 pre[s]=s; 22 q.push(s); 23 visit[s]=true; 24 while(!q.empty()){ 25 p=q.front(); 26 q.pop(); 27 //认为节点的数组下标从1开始,用邻接矩阵存储 28 for(int i=1;i<=n;++i){ 29 if(r[p][i]>0&&!visit[i]){ 30 visit[i]=true; 31 pre[i]=p; 32 if(i==t) 33 return true; 34 q.push(i); 35 } 36 } 37 } 38 return false; 39 } 40 int EK(int s,int t){ 41 //inc表示增广路可增加的流量 42 int maxflow=0,inc; 43 while(bfs(s,t)){ 44 //坑:每次循环一开始都要置inc为inf 45 inc=inf; 46 for(int i=t;i!=s;i=pre[i]){ 47 if(inc>r[pre[i]][i]){ 48 inc=r[pre[i]][i]; 49 } 50 } 51 //这里要求如果两点之间没有边时权重r初始化为0 52 for(int i=t;i!=s;i=pre[i]){ 53 54 r[pre[i]][i]-=inc; 55 r[i][pre[i]]+=inc; 56 } 57 maxflow+=inc; 58 } 59 return maxflow; 60 } 61 void startEK(){ 62 int a,b,c; 63 int ans; 64 65 while(~scanf("%d%d",&n,&m)){ 66 67 memset(r,0,sizeof(r)); 68 for(int i=0;i<m;++i){ 69 scanf("%d%d%d",&a,&b,&c); 70 r[a][b]+=c; 71 //看是否为双向路 72 //r[b][a]=c; 73 } 74 //默认s=1,t=n 75 ans=EK(1,n); 76 printf("%d ",ans); 77 } 78 return; 79 } 80 int main() 81 { 82 startEK(); 83 }