最大流的最短增益路径模版

来源:互联网 发布:关闭mysql 编辑:程序博客网 时间:2024/06/06 10:01

#define MAX 201
#define Inf 1<<20
#define MIN(x,y) ((x) < (y) ? (x) : (y))

 

 

//-------------------------------------------------------
//总结:利用队列进行广度探索,标记每个点的父结点和可再容纳的最大流量,
//探测到汇点时,汇点的可再容纳流量即是增益的流量,
//反复进行,直到不能探测到汇点为止。
//-------------------------------------------------------
//参数:节点数n,矩阵mat[][],源点source,汇点sink,每条边的流量 flow[][]
//返回:最大流 每条边的流量flow
int ford_fulkerson(int n,int mat[][MAX],int source,int sink,int flow[][MAX])
{
 //d[]用来表示还能容纳的容量
 int pre[MAX],que[MAX],d[MAX],p,q,t,i,j;
 //源点和汇点相同则返回
    if (source==sink)                                             
  return Inf;
 //初始化每条边的流量
 for (i=0;i<n;i++)                                             
  for (j=0;j<n;j++)
   flow[i][j] = 0;
  
  //反复标记,反复查找增益路径
  while(1)
  {
   //pre用来标记父结点,前驱节点,标记为0表示还为找到前驱节点
   for (i=0;i<n;i++)
    pre[i]=0;
   t= source;
   pre[source]=source+1;
   d[source]=Inf;
   //广度探索 que是用数组模拟的队列
   for (p=q=0;p<=q && !pre[sink];t=que[p++])
   {
    for (i=0;i<n;i++)
    {
     //前向边
     if (!pre[i] && mat[t][i]-flow[t][i] > 0){
      //i加入队列
      que[q++] = i;
      //标记第i + 1个顶点的前驱为第t + 1个顶点
      pre[i]=t+1;
      d[i] = MIN(d[t],mat[t][i] - flow[t][i]);
     }
     //后向边
     else if (!pre[i] && (j=flow[i][t]) > 0){
      que[q++]=i;
      //第i + 1个顶点的前驱为第t + 1个顶点,因为是后向边,加上-标记,整个成负数
      pre[i]=-t-1;
      d[i] = MIN(d[t],flow[i][t]);
     }
    }
   }
   //结束,不能标记汇点,也就是说不存在该条路径
   if (!pre[sink]) break;
   //回溯。。。
   //从汇点开始增加边的流量,直到源点
   for (i=sink;i!=source;)
   {
    //正向边
    if (pre[i] > 0){
     flow[pre[i]-1][i] += d[sink];
     i=pre[i]-1;
    }
    //反向边
    else{
     flow[i][-pre[i]-1] -= d[sink];
     i=-pre[i]-1;
    }
   }
  }
  //把和源点相接的边的流量相加即最大流量
  j = 0;
  for (i=0;i<n;i++)
   j+=flow[source][i];
  return j;
}


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/GoOnDrift/archive/2010/08/23/5832666.aspx

原创粉丝点击