POJ_1273_Drainage-Ditchs_图论_最大流



http://poj.org/problem?id=1273



总结一下:
第一:这是第一到最大流问题的求解;edmons_karp算法;
第二:基础运用很重要,题目要清楚;思路要清晰;
 



Hint

题意:现在有m个池塘(从1到m开始编号,1为源点,m为汇点),及n条水渠,给出这n条水渠所连接的池塘和所能流过的水量,求水渠中所能流过的水的最大容量.一道基础的最大流题目,用增广路算法Edmonds_Karp求解。
其实就是以点1为s,以点m为t,求最大流,但是要注意输入的路径可以重复


CODE

#include <iostream>
#include "stdio.h"
using namespace std;
#include <string.h>
#include <queue>
const int N=201;
const int INF=9999999;
int n,m,sum,s,t,w;
int a[N],p[N],cap[N][N];

int min(int a,int b)
{
    return a<b?a:b;
}

void edmonds_karp()
{
    int i,u,v;
    queue<int> q;
    while(1)
    {
        memset(a,0,sizeof(a));
        a[s]=INF;
        q.push(s);
        while(!q.empty())
        {
            u=q.front();
            q.pop();
            for(v=1;v<=m;v++)
              if(!a[v]&&cap[u][v]>0)
                {
                    p[v]=u;
                    q.push(v);
                    a[v]=min(a[u],cap[u][v]);
                }
        }
        if(a[m]==0)  break;
        sum+=a[m];
        for(i=m;i!=s;i=p[i])
           {
               cap[p[i]][i]-=a[m];
               cap[i][p[i]]+=a[m];
           }
    }
    printf("%d\n",sum);
}

int main()
{
   int u,v;
   while(scanf("%d %d",&n,&m)!=EOF)
   {
       s=1;t=m;
       sum=0;
      memset(cap,0,sizeof(cap));
      while(n--)
      {
          scanf("%d%d%d",&u,&v,&w);
          cap[u][v]+=w;
      }
    edmonds_karp();
   }
   return 0;
}


其他的一些差不多的:
#include<iostream>
#include<queue>
using namespace std;
const int N=201;
const int INF=99999999;
int n,m,sum,s,t;//s,t为始点和终点
int flow[N][N],cap[N][N],a[N],p[N];
//分别为:flow[u][v]为<u,v>流量、cap[u][v]为<u,v>容量、a[i]表示源点s到节点i的路径上的最小残留量、p[i]记录i的前驱
int min(int a,int b)
{
return a<=b?a:b;
}
void Edmonds_Karp()
{
int i,u,v;
queue<int>q;//队列,用bfs找增广路
while(1)
{
   memset(a,0,sizeof(a));//每找一次,初始化一次
   a[s]=INF;
   q.push(s);//源点入队
   while(!q.empty())
   {
    u=q.front();
    q.pop();
    for(v=1;v<=m;v++)
    {
     if(!a[v]&&flow[u][v]<cap[u][v])
     {
      p[v]=u;
      q.push(v);
      a[v]=min(a[u],cap[u][v]-flow[u][v]);//s-v路径上的最小残量
     }
    }
   }
   if(a[m]==0)//找不到增广路,则当前流已经是最大流
    break;
   sum+=a[m];//流加上
   for(i=m;i!=s;i=p[i])// //从汇点顺着这条增广路往回走
   {
    flow[p[i]][i]+=a[m];//更新正向流量
    flow[i][p[i]]-=a[m];//更新反向流量
   }
}
printf("%d\n",sum);
}

int main()
{
//freopen("in.txt","r",stdin);
int v,u,w;
    while(scanf("%d%d",&n,&m)!=EOF)
{
   s=1;//从1开始
   t=m;//m为汇点
   sum=0;//记录最大流量
   memset(flow,0,sizeof(flow));//初始化
   memset(cap,0,sizeof(cap));
   while(n--)
   {
    scanf("%d%d%d",&u,&v,&w);
    cap[u][v]+=w;//注意图中可能出现相同的边
   }
   Edmonds_Karp();
}
return 0;
}

空间优化:

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

#include<iostream>
#include<queue>
using namespace std;
const int N=201;
const int INF=99999999;
int n,m,sum,s,t,w;//s,t为始点和终点
int cap[N][N],a[N],p[N];
int min(int a,int b)
{
return a<=b?a:b;
}
void Edmonds_Karp()
{
int i,u,v;
queue<int>q;//队列,用bfs找增广路
while(1)
{
   memset(a,0,sizeof(a));//每找一次,初始化一次
   a[s]=INF;
   q.push(s);//源点入队
   while(!q.empty())
   {
    u=q.front();
    q.pop();
    for(v=1;v<=m;v++)
    {
     if(!a[v]&&cap[u][v]>0)
     {
      p[v]=u;
      q.push(v);
      a[v]=min(a[u],cap[u][v]);//s-v路径上的最小残量
     }

    }
   }
   if(a[m]==0)//找不到增广路,则当前流已经是最大流
    break;
   sum+=a[m];//流加上
   for(i=m;i!=s;i=p[i])// //从汇点顺着这条增广路往回走
   {
    cap[p[i]][i]-=a[m];//更新正向流量
    cap[i][p[i]]+=a[m];//更新反向流量
   }
}
printf("%d\n",sum);
}

int main()
{
// freopen("in.txt","r",stdin);
int v,u;
    while(scanf("%d%d",&n,&m)!=EOF)
{
   s=1;//从1开始
   t=m;//m为汇点
   sum=0;//记录最大流量
   memset(cap,0,sizeof(cap));//初始化
   while(n--)
   {
    scanf("%d%d%d",&u,&v,&w);
    cap[u][v]+=w;//注意图中可能出现相同的边
   }
   Edmonds_Karp();
}
return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值