首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >推挽算法的实现

推挽算法的实现
EN

Stack Overflow用户
提问于 2013-10-18 21:31:22
回答 1查看 3K关注 0票数 1

我从topcoder站点学习了推送重标签算法:http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=maxflowPushRelabel,我认为实现有问题。当节点饱和时,如何将多余的流推回节点。例如:

当找到从1到3的最大流量时,在一个阶段我需要将流量从2推到1(因为2没有传出的边)。但是在先入先出算法的代码实现中,行号16处的循环是从0 to G[u].size()运行的。既然2没有从2到1的任何边,它怎么能把流推回1呢?

如果需要的话,下面是我糟糕的实现:

代码语言:javascript
运行
复制
#define DEBUG       //comment when you have to disable all debug macros.
#define LOCAL
#define NDEBUG    //comment when all assert statements have to be disabled.
#include <iostream>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <bitset>
#include <climits>
#include <ctime>
#include <algorithm>
#include <functional>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <sys/time.h>
#include <iomanip>
#include <cstdarg>
#include <utility> //std::pair
#include <cassert>
#define tr(c,i) for(typeof(c.begin()) i = (c).begin(); i != (c).end(); i++) 
#define present(c,x) ((c).find(x) != (c).end()) 
#define all(x) x.begin(), x.end()
#define pb push_back
#define mp make_pair
#define log2(x) (log(x)/log(2))
#define ARRAY_SIZE(arr) (1[&arr]-arr)      
#define INDEX(arr,elem)        (lower_bound(all(arr),elem)-arr.begin())
#define lld long long int
#define MOD 1000000007
#define gcd __gcd
#define equals(a,b) (a.compare(b)==0)    //for strings only
using namespace std;



struct Graph{
   lld numV;
   vector<lld> *adj;
   lld **flow, **cap, **cf, *height, *excess;
      inline void SET0(lld *array)
      {
         for(lld i=0;i<=numV;i++)
            array[i]=0;
      }
   Graph(lld _numV)
      {
         numV=_numV;
         lld i;
         /* allocating memory....*/
         flow = new lld*[numV+1];
         for(i=0;i<=numV;i++)
            flow[i] = new lld[numV+1], SET0(flow[i]);
         cap = new lld*[numV+1];
         for(i=0;i<=numV;i++)
            cap[i] = new lld[numV+1], SET0(cap[i]);
         cf = new lld*[numV+1];
         for(i=0;i<=numV;i++)
            cf[i] = new lld[numV+1], SET0(cf[i]);

         height = new lld[numV+1];
         excess = new lld[numV+1];
         SET0(height);
         SET0(excess);
         adj = new vector<lld>[numV+1];
      }
   void addEdge(lld u, lld v, lld uv)
      {
         adj[u].push_back(v);
         cap[u][v] = uv;
         cf[u][v] = uv;
      }

   void initialize_preflow(lld source)
      {
         lld i, v;
         height[source] = numV-1;

         tr(adj[source],it)
         {
            v = *it;
            flow[source][v] = cap[source][v];
            flow[v][source] = -cap[source][v];
            excess[v] += cap[source][v];
            excess[source] -=cap[source][v];
            cf[source][v] = cap[source][v]-flow[source][v];
            cf[v][source] = cap[v][source]-flow[v][source];
         }
      }
   void push(lld u, lld v)
      {
         lld push_val = min(cf[u][v], excess[u]);
         flow[u][v] += push_val;
         flow[v][u] = -flow[u][v];
         excess[u] -=push_val;
         excess[v] +=push_val;
         cf[u][v] = cap[u][v]-flow[u][v];
         cf[v][u] = cap[v][u]-flow[v][u];
      }
   lld max_flow(lld source, lld sink)
      {
         initialize_preflow(source);
         queue<lld> q;
         bool considered[numV+1];
         lld u, v, m, i;
         memset(considered, false, sizeof(considered));
         tr(adj[source], it)
         {
            v = *it;
            if(v!=sink)
            {
               q.push(v);
               considered[v] = true;
            }
         }
         bool flag;
         u = -1;
         while(!q.empty())
         {

            u = q.front();
            m = -1;
            for(i=0;i<adj[u].size() && excess[u]>0; i++)
            {

               v = adj[u][i];
               if(cf[u][v]>0)
               {
                  if(height[u]>height[v])
                  {
                     push(u,v);
                     if(!considered[v] && v!=sink && v!=source)
                     {
                        considered[v] = true;
                        q.push(v);
                     }
                  }
                  else if(m==-1) m = height[v];
                  else   m = min(m, height[v]);
               }
            }

            if(adj[u].empty()) {q.pop();continue;}
            if(excess[u]!=0) height[u] = m+1;
            else
            {
               q.pop();
               considered[u] = false;
            }
         }
         return excess[sink];
      }

};

template<class T>
inline void inputInt(T &n )
{
   n=0;
   T ch=getchar_unlocked();
     while( ch < '0' || ch > '9' )
      ch=getchar_unlocked();
      while(  ch >= '0' && ch <= '9' )
       n = (n<<3)+(n<<1) + ch-'0', ch=getchar_unlocked();
}

int main()
{
#ifdef LOCAL
   freopen("input.in","r",stdin);
#endif
   lld e,u,v,n,c;
   //cout<<"V:"<<endl;
   cin>>n>>e;

   Graph g(n);
   while(e--)
   {

      inputInt(u);
      inputInt(v);
      inputInt(c);
      if(u!=v)
      {
         if(g.cf[u][v])
            g.cf[u][v]=g.cf[v][u]=g.cap[u][v]=g.cap[v][u]+c;
         else g.addEdge(u,v,c);
      }
   }
   cout<<g.max_flow(1,n)<<endl;

}
EN

回答 1

Stack Overflow用户

发布于 2014-04-30 22:48:10

我刚刚重新实现了topcoder的推送算法。我也面临着同样的问题。这是在塔楼里描述的某种不好的东西。但是解决方案是,在有向图的相反方向向图中添加一个边--每个边的容量为0!

例如,将边(3,1)和边(2,1)添加到上面的示例图中,两者都具有0的容量。

如果你有一个无向图,这个问题当然是不必要的,因为你把两个相同的边(u,v)和(v,u)相加到你的图中。

我希望我能帮上忙,如果没有,只需问:)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19459357

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档