zoukankan      html  css  js  c++  java
  • 最大流poj1273(三大算法解析)

    模板题:(poj1273)
     
    Drainage Ditches
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions:87924   Accepted: 34130

    Description

    Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage ditches so that Bessie's clover patch is never covered in water. Instead, the water is drained to a nearby stream. Being an ace engineer, Farmer John has also installed regulators at the beginning of each ditch, so he can control at what rate water flows into that ditch. 
    Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network. 
    Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle. 

    Input

    The input includes several cases. For each case, the first line contains two space-separated integers, N (0 <= N <= 200) and M (2 <= M <= 200). N is the number of ditches that Farmer John has dug. M is the number of intersections points for those ditches. Intersection 1 is the pond. Intersection point M is the stream. Each of the following N lines contains three integers, Si, Ei, and Ci. Si and Ei (1 <= Si, Ei <= M) designate the intersections between which this ditch flows. Water will flow through this ditch from Si to Ei. Ci (0 <= Ci <= 10,000,000) is the maximum rate at which water will flow through the ditch.

    Output

    For each case, output a single integer, the maximum rate at which water may emptied from the pond.

    Sample Input

    5 4
    1 2 40
    1 4 20
    2 4 20
    2 3 30
    3 4 10
    

    Sample Output

    50

    Source

    题意:从1流到m的最大流。
    思路:最大流模板题。
    最大流EK算法
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<string.h>
     4 #include<queue>
     5 using namespace std;
     6 int n,m;
     7 int map[210][210];//存图 
     8 int flow[210];//一条可行流中的最小流(因为一条路径中流量是由最小的那个决定的) 
     9 int pre[210];//记录每个点的前驱 
    10 queue<int>Q;
    11 int bfs(int start,int ed){//查找可行流
    12     while(!Q.empty()) Q.pop();
    13     for(int i=1;i<=m;i++){
    14         pre[i]=-1;//将每个点的前驱赋值为-1 
    15     }
    16     pre[start]=0;//起点前驱为0 
    17     Q.push(start);
    18     flow[start]=0x3f3f3f3f;//初始化,方便找流量最小的那个路径 
    19     while(!Q.empty()){
    20         int index=Q.front();
    21         Q.pop();
    22         for(int i=1;i<=m;i++){
    23             if(pre[i]==-1&&map[index][i]>0){//没有被走过,且index->i的流量大于0 
    24                 pre[i]=index;//记录前驱(i的前驱是index) 
    25                 flow[i]=min(flow[index],map[index][i]);//更新flow 
    26                 Q.push(i);
    27             }
    28         }
    29     }
    30     if(pre[ed]==-1) return -1;//如果终点前驱是-1即代表没有路能到达终点即无增广路径 
    31     else return flow[ed];
    32 }
    33 int Max_flow(int start,int ed){
    34     int ans=0; 
    35     int cnt=0;
    36     while((cnt=bfs(start,ed))!=-1){
    37         int k=ed;
    38         while(k!=start){//迭代,查找需改变流量路径 
    39             int last=pre[k];
    40             map[last][k]-=cnt;//改变正向流量 
    41             map[k][last]+=cnt;//改变反向流量 
    42             k=last;
    43         }
    44         ans+=cnt;
    45     }
    46     return ans;
    47 }
    48 int main(){
    49     while(cin>>n>>m){
    50         memset(map,0,sizeof(map));
    51         memset(flow,0,sizeof(flow));
    52         int start,ed,flo;
    53         for(int i=0;i<n;i++){
    54             cin>>start>>ed>>flo;
    55             if(start==ed) continue;
    56             map[start][ed]+=flo;//可能输入有重边 
    57         }
    58         cout<<Max_flow(1,m)<<endl;
    59     }
    60     return 0;
    61 }
    View Code

     最大流Ford-Fulkerson算法

     1 #include<iostream>
     2 #include<string.h>
     3 #include<queue>
     4 using namespace std;
     5 int map[300][300];
     6 int n,m;
     7 bool vis[300];//标记该点有没有用过 
     8 int dfs(int start,int ed,int cnt){//cnt是查找到的增广路中流量最小的边 
     9     if(start==ed) return cnt;//起点等于终点,即已经查到一条可行增广路 
    10     for(int i=1;i<=m;i++){//以起点start遍历与它相连的每一条边 
    11         if(map[start][i]>0&&!vis[i]){//这条边是否可行 
    12             vis[i]=true;//标记已经走过 
    13             int d=dfs(i,ed,min(cnt,map[start][i]));//递归查找 
    14             if(d>0){//回溯时更行map,这和EK的迭代更行差不多 
    15                 map[start][i]-=d;
    16                 map[i][start]+=d;
    17                 return d; 
    18             }
    19         }
    20     }
    21     return 0;//没找到 
    22 }
    23 int Max_flow(int start,int ed){
    24     int ans=0;
    25     while(true){
    26         memset(vis,false,sizeof(vis));
    27         int f=dfs(start,ed,0x3f3f3f3f);//查找增广路 
    28         //cout<<f<<endl;
    29         if(f==0) return ans;//没有增广路了 
    30         ans+=f;
    31     }
    32 }
    33 int main(){
    34     int start,ed,w;
    35     while(cin>>n>>m){
    36         memset(map,0,sizeof(map));
    37         for(int i=0;i<n;i++){
    38             cin>>start>>ed>>w;
    39             if(start==ed) continue;
    40             map[start][ed]+=w;
    41         }
    42         cout<<Max_flow(1,m)<<endl;
    43     }
    44     return 0;
    45 }
    View Code

    前面两个算法不同的是一个是用dfs查找增广路,一个是用bfs查找。

    观察前面的dfs算法,对于层次相同的边,会经过多次重复运算,很浪费时间(如有这么一组数据,(1 2 2)(1 3 2) (2 4 1) (3 4 1)那么【1】【2,3】【4】就是他们的层次,所以2->3就是没必要走的 ),那么,可以考虑先对原图分好层产生新的层次图,即保存了每个点的层次,注意,很多人会把这里的边的最大容量跟以前算最短路时的那个权值混淆,其实这里每个点之间的距离都可以看作单位距离,然后对新图进行dfs,这时的dfs就非常有层次感,有筛选感了,同层次的点不可能在同一跳路径中,直接排除。那么运行速度就会快很多了。

    这就是dinic算法的思想

    最大流dinic算法

     1 #include<iostream>
     2 #include<queue>
     3 #include<string.h>
     4 using namespace std;
     5 int dep[300];//dep是层次 
     6 int map[300][300];
     7 int n,m;
     8 bool bfs(int start,int ed){//图分层 
     9     if(start==ed) return false;//防止输入的起点与终点相等 
    10     queue<int>Q;
    11     while(!Q.empty()) Q.pop();
    12     Q.push(start);
    13     memset(dep,-1,sizeof(dep));//先将所有点的层次变为-1 
    14     dep[start]=0;//第一层定义为0 
    15     while(!Q.empty()){
    16         int index=Q.front();//起点 
    17         Q.pop();
    18         for(int i=1;i<=m;i++){//与index相连的边(index->i) 
    19             if(map[index][i]>0&&dep[i]==-1){//没被分过成且map>0 
    20                 dep[i]=dep[index]+1;//i的层是index层+1 
    21                 Q.push(i);
    22             }
    23         }
    24     }
    25     return dep[ed]!=-1;//如果终点层等于-1,即是图已经无法进行分层 
    26 }
    27 int bt=0;
    28 int dfs(int start,int ed,int cnt){//寻找增广路 (与Ford-Fulkerson算法差不多) 
    29     if(start==ed) return cnt;
    30     int d;
    31     for(int i=1;i<=m;i++){
    32         if(dep[i]==dep[start]+1&&map[start][i]>0){//用层次去查询,排除了走相同层 
    33             cout<<bt++<<":"<<start<<"  ,  "<<i<<"               "<<dep[i]<<"   ,"<<dep[start]<<endl;
    34                 d = dfs(i,ed, min(cnt, map[start][i]));
    35                 if(d>0){
    36                     map[start][i]-=d;
    37                     map[i][start]+=d;
    38                     return d;
    39                 }
    40             }
    41         }
    42     return 0;
    43 }
    44 int Max_flow(int start,int ed){
    45     int ans=0;
    46     while(bfs(start,ed)){//将图进行分层 
    47         while(true){
    48             int d=dfs(start,ed,0x3f3f3f3f);
    49             if(d==0) break;//该分层图已经无法找到增广路 
    50             ans+=d;
    51         }
    52     }
    53     return ans;//所有增广路已经查找完毕 
    54 }
    55 int main(){
    56     int start,ed,w;
    57     while(cin>>n>>m){
    58         memset(map,0,sizeof(map));
    59         for(int i=0;i<n;i++){
    60             cin>>start>>ed>>w;
    61             map[start][ed]+=w;
    62         }
    63         cout<<Max_flow(1,m)<<endl;
    64     }
    65     return 0;
    66 }
    View Code
  • 相关阅读:
    二分查找
    Linux下查找目录中所有文件中含有某个字符串,并且只打印出文件名
    编码规范
    Cookie和Session的选择,以及如何解决分布式系统下各个服务器之间Session不统一的问题
    Mac VMware Fusion 11.5 虚拟机带密钥
    快速排序
    python装饰器
    商品详情页
    hadoop跑wordcount报expected org.apache.hadoop.io.Text, received org.apache.hadoop.io.LongWritable
    CentOS7设置共享文件夹不显示问题
  • 原文地址:https://www.cnblogs.com/liuzuolin/p/10531553.html
Copyright © 2011-2022 走看看