• [转载 ]POJ 1273 最大流模板


    转载

    百度文库花了5分下的可怜 不过确实是自己需要的东西吐舌头
    经典的最大流题POJ1273

    ——其他练习题 POJ3436 、

    题意描述:

    现在有m个池塘(从1到m开始编号,1为源点,m为汇点),及n条水渠,给出这n条水渠所连接的池塘和所能流过的水量,求水渠中所能流过的水的最大容量.一道基础的最大流题目。但是模板小心使用,目前只是求单源点的最大流。

    参考数据:

    输入:

    5 4

    1 2 40

    1 4 20

    2 4 20

    2 3 30

    3 4 10

    输出:

    50

    程序实现:

    增广路算法Edmonds_Karp

     1 //poj1273_Ek.cpp
     2 #include<iostream>
     3 #include<queue>
     4 using namespace std;
     5 const int N=201;
     6 const int INF=99999999;
     7 int n,m,sum,s,t;//s,t为始点和终点
     8 int flow[N][N],cap[N][N],a[N],p[N];
     9 //分别为:flow[u][v]为<u,v>流量、cap[u][v]为<u,v>容量、a[i]表示源点s到节点i的路径上的最小残留量、p[i]记录i的前驱
    10 int min(int a,int b)
    11 {
    12 return a<=b?a:b;
    13 }
    14 void Edmonds_Karp()
    15 {
    16 int i,u,v;
    17 queue<int>q;//队列,用bfs找增广路
    18 while(1)
    19 {
    20    memset(a,0,sizeof(a));//每找一次,初始化一次
    21    a[s]=INF;
    22    q.push(s);//源点入队
    23    while(!q.empty())
    24    {
    25     u=q.front();
    26     q.pop();
    27     for(v=1;v<=m;v++)
    28     {
    29      if(!a[v]&&flow[u][v]<cap[u][v])
    30      {
    31       p[v]=u;
    32       q.push(v);
    33       a[v]=min(a[u],cap[u][v]-flow[u][v]);//s-v路径上的最小残量
    34      }
    35     }
    36    }
    37    if(a[m]==0)//找不到增广路,则当前流已经是最大流
    38     break;
    39    sum+=a[m];//流加上
    40    for(i=m;i!=s;i=p[i])// //从汇点顺着这条增广路往回走
    41    {
    42     flow[p[i]][i]+=a[m];//更新正向流量
    43     flow[i][p[i]]-=a[m];//更新反向流量
    44    }
    45 }
    46 printf("%d
    ",sum);
    47 }
    48 int main()
    49 {
    50 //freopen("in.txt","r",stdin);
    51 int v,u,w;
    52     while(scanf("%d%d",&n,&m)!=EOF)
    53 {
    54    s=1;//从1开始
    55    t=m;//m为汇点
    56    sum=0;//记录最大流量
    57    memset(flow,0,sizeof(flow));//初始化
    58    memset(cap,0,sizeof(cap));
    59    while(n--)
    60    {
    61     scanf("%d%d%d",&u,&v,&w);
    62     cap[u][v]+=w;//注意图中可能出现相同的边
    63    }
    64    Edmonds_Karp();
    65 }
    66 return 0;
    67 }
    View Code

    空间优化: 

    在程序实现的时候,我们通常只是用一个cap数组来记录容量,而不记录流量,当流量+1的时候,我们可以通过容量-1来实现,以方便程序的实现。正向用cap[u][v],则反向用cap[v][u]表示。

     1 #include<iostream>
     2 #include<queue>
     3 using namespace std;
     4 const int N=201;
     5 const int INF=99999999;
     6 int n,m,sum,s,t,w;//s,t为始点和终点
     7 int cap[N][N],a[N],p[N];
     8 int min(int a,int b)
     9 {
    10 return a<=b?a:b;
    11 }
    12 void Edmonds_Karp()
    13 {
    14 int i,u,v;
    15 queue<int>q;//队列,用bfs找增广路
    16 while(1)
    17 {
    18    memset(a,0,sizeof(a));//每找一次,初始化一次
    19    a[s]=INF;
    20    q.push(s);//源点入队
    21    while(!q.empty())
    22    {
    23     u=q.front();
    24     q.pop();
    25     for(v=1;v<=m;v++)
    26     {
    27      if(!a[v]&&cap[u][v]>0)
    28      {
    29       p[v]=u;
    30       q.push(v);
    31       a[v]=min(a[u],cap[u][v]);//s-v路径上的最小残量
    32      }
    33     }
    34    }
    35    if(a[m]==0)//找不到增广路,则当前流已经是最大流
    36     break;
    37    sum+=a[m];//流加上
    38    for(i=m;i!=s;i=p[i])// //从汇点顺着这条增广路往回走
    39    {
    40     cap[p[i]][i]-=a[m];//更新正向流量
    41     cap[i][p[i]]+=a[m];//更新反向流量
    42    }
    43 }
    44 printf("%d
    ",sum);
    45 }
    46 int main()
    47 {
    48 // freopen("in.txt","r",stdin);
    49 int v,u;
    50     while(scanf("%d%d",&n,&m)!=EOF)
    51 {
    52    s=1;//从1开始
    53    t=m;//m为汇点
    54    sum=0;//记录最大流量
    55    memset(cap,0,sizeof(cap));//初始化
    56    while(n--)
    57    {
    58     scanf("%d%d%d",&u,&v,&w);
    59     cap[u][v]+=w;//注意图中可能出现相同的边
    60    }
    61    Edmonds_Karp();
    62 }
    63 return 0;
    64 }
    View Code

    Dinic邻接矩阵实现

     1 #include <cstdio> 
     2  #include <cstring> 
     3  #include <cstdlib> 
     4  #include <iostream> 
     5  #define min(x,y) ((x<y)?(x):(y)) 
     6  using namespace std; 
     7  const int MAX=0x5fffffff;// 
     8  int tab[250][250];//邻接矩阵  
     9  int dis[250];//距源点距离,分层图  
    10  int q[2000],h,r;//BFS队列 ,首,尾  
    11  int N,M,ANS;//N:点数;M,边数  
    12  int BFS() 
    13  { int i,j; 
    14  memset(dis,0xff,sizeof(dis));//以-1填充  
    15  dis[1]=0; 
    16  h=0;r=1; 
    17  q[1]=1; 
    18  while (h<r) 
    19  { 
    20  j=q[++h]; 
    21  for (i=1;i<=N;i++) 
    22  if (dis[i]<0 && tab[j][i]>0) 
    23  { 
    24  dis[i]=dis[j]+1;  
    25  q[++r]=i; 
    26  } 
    27  } 
    28  if (dis[N]>0) 
    29  return 1; 
    30  else 
    31  return 0;//汇点的DIS小于零,表明BFS不到汇点  
    32  } 
    33  //Find代表一次增广,函数返回本次增广的流量,返回0表示无法增广  
    34  int find(int x,int low)//Low是源点到现在最窄的(剩余流量最小)的边的剩余流量 
    35  { 
    36  int i,a=0; 
    37  if (x==N)return low;//是汇点  
    38  for (i=1;i<=N;i++) 
    39  if (tab[x][i] >0 //联通  
    40  && dis[i]==dis[x]+1 //是分层图的下一层  
    41  &&(a=find(i,min(low,tab[x][i]))))//能到汇点(a <> 0)  
    42  { 
    43  tab[x][i]-=a; 
    44  tab[i][x]+=a; 
    45  return a; 
    46  } 
    47  return 0; 
    48    } 
    49  int main() 
    50  { 
    51  //freopen("ditch.in" ,"r",stdin ); 
    52  //freopen("ditch.out","w",stdout); 
    53  int i,j,f,t,flow,tans; 
    54  while (scanf("%d%d",&M,&N)!=EOF){ 
    55  memset(tab,0,sizeof(tab)); 
    56  for (i=1;i<=M;i++) 
    57  { 
    58  scanf("%d%d%d",&f,&t,&flow); 
    59  tab[f][t]+=flow; 
    60  } 
    61  // 
    62  ANS=0; 
    63  while (BFS())//要不停地建立分层图,如果BFS不到汇点才结束  
    64  { 
    65  while(tans=find(1,0x7fffffff))ANS+=tans;//一次BFS要不停地找增广路,直到找不到为止  
    66  } 
    67  printf("%d
    ",ANS); 
    68  } 
    69   //system("pause"); 
    70  }
    View Code

    Dinic邻接表实现

      1 //#define LOCAL
      2 #include <stdio.h>
      3 #include <string.h>
      4 #include <queue>
      5 using namespace std;
      6 
      7 #define MAXN 210
      8 #define INF 0x3f3f3f3f
      9 
     10 struct Edge
     11 {
     12     int st, ed;
     13     int c;
     14     int next;
     15 }edge[MAXN << 1];
     16 
     17 int n, m;
     18 int s, t;
     19 int ans;
     20 int e = 0; 
     21 int head[MAXN];
     22 int d[MAXN];
     23 
     24 int min(int a, int b)
     25 {
     26     return a < b ? a : b;
     27 }
     28 
     29 void init()
     30 {
     31     int i, j;
     32     int a, b, c; 
     33     s = 1;
     34     t = m;
     35     e = 0;
     36     ans = 0;
     37     memset(head, -1, sizeof(head));
     38     for(i = 1; i <= n; i++)
     39     {
     40         scanf("%d%d%d", &a, &b, &c);
     41         edge[e].st = a;
     42         edge[e].ed = b;
     43         edge[e].c = c;
     44         edge[e].next = head[a];
     45         head[a]= e++;
     46         edge[e].st = b;
     47         edge[e].ed = a;
     48         edge[e].next = head[b];
     49         head[b] = e++;
     50     }
     51 }
     52 
     53 int bfs()
     54 {
     55     memset(d, -1, sizeof(d));
     56     queue<int> q;
     57     d[s] = 0;
     58     q.push(s);
     59     int i;
     60     int cur;
     61     while(!q.empty())
     62     {
     63         cur = q.front();
     64         q.pop();
     65         for(i = head[cur]; i != -1; i = edge[i].next)
     66         {
     67             if(d[edge[i].ed] == -1 && edge[i].c > 0)
     68             {
     69                 d[edge[i].ed] = d[cur] + 1; 
     70                 q.push(edge[i].ed);
     71             }    
     72         }
     73     }
     74     if(d[t] < 0)
     75         return 0;
     76     return 1;
     77 }
     78 
     79 int dinic(int x, int flow)
     80 {
     81     if(x == t)
     82         return flow;
     83     int i, a;
     84     for(i = head[x]; i != -1; i = edge[i].next)
     85     {
     86         if(d[edge[i].ed] == d[x] + 1 && edge[i].c > 0 && (a = dinic(edge[i].ed, min(flow, edge[i].c))))
     87         {
     88             edge[i].c -= a;
     89             edge[i ^ 1].c += a;
     90             return a;    
     91         }
     92     }
     93     return 0;
     94 }
     95 
     96 void solve()
     97 {
     98     while(scanf("%d%d", &n, &m) != EOF)
     99     {
    100         init();
    101         while(bfs())
    102         {
    103             int increment;
    104             increment = dinic(1, INF);
    105                 ans +=  increment; 
    106         }
    107         printf("%d
    ", ans);
    108     }
    109 }
    110 
    111 int main()
    112 {
    113 #ifdef LOCAL
    114     freopen("poj1273.txt", "r", stdin);
    115     // freopen(".txt", "w", stdout);
    116 #endif
    117     solve();
    118     return 0;
    119 }
    View Code

    SAP实现:poj1273_SAP.cpp

    /* 

    编者感悟:

    sap学了很长时间,一直不敢下手写,结果就是不写永远不会真正的理解算法的含义,sap理论很多算法书上都有讲解,但我还是建议看数学专业 图论的书,比如 《有向图的理论,算法及应用》,这本书的内容非常棒,相信看过的都知道吧,比其他算法书上讲的透多了。
    SAP有个优化就是 当出现断链时,就可以直接退出,还有个优化是当前弧的优化,这两个优化只需要一句话+一个数组就解决了,相当实惠,好的ISAP执行的效率真的非常高,我写的ISAP用的是链式前向星法表示。
    这个就算是模板了吧,虽然写的不是很好。。

    */

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<memory.h>
      4 #include<cmath>
      5 using namespace std;
      6 #define MAXN 500
      7 #define MAXE 40000
      8 #define INF 0x7fffffff
      9 long ne,nv,tmp,s,t,index;
     10 struct Edge{
     11     long next,pair;
     12     long v,cap,flow;
     13 }edge[MAXE];
     14 long net[MAXN];
     15 long ISAP()
     16 {
     17     long numb[MAXN],dist[MAXN],curedge[MAXN],pre[MAXN];
     18     long cur_flow,max_flow,u,tmp,neck,i;
     19     memset(dist,0,sizeof(dist));
     20     memset(numb,0,sizeof(numb));
     21     memset(pre,-1,sizeof(pre));
     22     for(i = 1 ; i <= nv ; ++i)
     23         curedge[i] = net[i];
     24     numb[nv] = nv;
     25     max_flow = 0;
     26     u = s;
     27     while(dist[s] < nv)
     28     {
     29         /* first , check if has augmemt flow */
     30         if(u == t)
     31         {
     32             cur_flow = INF;
     33             for(i = s; i != t;i = edge[curedge[i]].v) 
     34             {  
     35                 if(cur_flow > edge[curedge[i]].cap)
     36                 {
     37                     neck = i;
     38                     cur_flow = edge[curedge[i]].cap;
     39                 }
     40             }
     41             for(i = s; i != t; i = edge[curedge[i]].v)
     42             {
     43                 tmp = curedge[i];
     44                 edge[tmp].cap -= cur_flow;
     45                 edge[tmp].flow += cur_flow;
     46                 tmp = edge[tmp].pair;
     47                 edge[tmp].cap += cur_flow;
     48                 edge[tmp].flow -= cur_flow;
     49             }
     50             max_flow += cur_flow;
     51             u = neck;
     52         }
     53         /* if .... else ... */
     54         for(i = curedge[u]; i != -1; i = edge[i].next)
     55             if(edge[i].cap > 0 && dist[u] == dist[edge[i].v]+1)
     56                 break;
     57         if(i != -1)
     58         {
     59             curedge[u] = i;
     60             pre[edge[i].v] = u;
     61             u = edge[i].v;
     62         }else{
     63             if(0 == --numb[dist[u]]) break;
     64             curedge[u] = net[u];
     65             for(tmp = nv,i = net[u]; i != -1; i = edge[i].next)
     66                 if(edge[i].cap > 0)
     67                     tmp = tmp<dist[edge[i].v]?tmp:dist[edge[i].v];
     68             dist[u] = tmp + 1;
     69             ++numb[dist[u]];
     70             if(u != s) u = pre[u];
     71         }
     72     }
     73     
     74     return max_flow;
     75 }
     76 int main() {
     77     long i,j,np,nc,m,n;
     78     long a,b,val;
     79     long g[MAXN][MAXN];
     80     while(scanf("%d%d",&ne,&nv)!=EOF)
     81     {
     82         s = 1;
     83         t = nv;
     84         memset(g,0,sizeof(g));
     85         memset(net,-1,sizeof(net));
     86         for(i=0;i<ne;++i)
     87         {
     88             scanf("%ld%ld%ld",&a,&b,&val);
     89             g[a][b] += val;
     90          }
     91          for(i=1;i<=nv;++i)
     92              for(j = i; j <= nv;++j)
     93                  if(g[i][j]||g[j][i])
     94                  {
     95                      edge[index].next = net[i];
     96                      edge[index].v = j;
     97                      edge[index].cap = g[i][j];
     98                      edge[index].flow = 0;
     99                      edge[index].pair = index+1;
    100                      net[i] = index++;
    101                      edge[index].next = net[j];
    102                      edge[index].v = i;
    103                      edge[index].cap = g[j][i];
    104                      edge[index].flow = 0;
    105                      edge[index].pair = index-1;
    106                      net[j] = index++;
    107                  }
    108         printf("%ld
    ",ISAP());
    109     }
    110     return 0;
    111 }
    View Code
  • 相关阅读:
    C#(99):Queue<T>队列与Stack<T>堆栈
    C#(99):字典Dictionary<Tkey.TValue>与SortedList
    C#(99):列表:List<T>与HashSet和只读集合
    C#(99):C#数组Array
    C#(99):枚举类型与位域枚举Enum
    C#(99):结构类型:Struct
    C#(99):定义类成员(属性、方法、索引、运算符、事件)、接口实现
    C#(99):定义类、System.Object对象、构造函数与析构函数、抽象类与静态类
    SuperSocket.ClientEngine介绍
    C#(99):五、并行编程
  • 原文地址:https://www.cnblogs.com/ACMERY/p/4782022.html
Copyright © 2020-2023  润新知