1. 程式人生 > >最大流的基本演算法(ff演算法&&dinic演算法&&push-rebeal演算法)poj1273

最大流的基本演算法(ff演算法&&dinic演算法&&push-rebeal演算法)poj1273

最大流的基本概念有以下幾點:

              1.殘存網路:即為一條管道被佔用了一部分流量之後所剩下的流量。在網路流中,圖被看為一個有向圖,殘存流量向量相加後永遠不變。這一點有點像基爾霍夫定律。

              2.在找到一個流之後,仍然存在的從源點到匯點的路徑。這叫做增廣路徑。加入增廣路徑後,流的容量一定能夠提升。尋找增廣路徑一般使用DFS或BFS。

ford-fulkerson演算法就是這樣,當有向圖中存在增廣路徑,即將這條增廣路徑加入流當中。當有向圖中無法再找到增廣路徑的時候,此時的流即為我們所要求的最大流。(依據為最大流最小割定理)。

題目地址:http://poj.org/problem?id=1273

這一題要求我們求這條排水系統最大的負載,是一個明顯的網路流問題。我們構造一個有向圖,然後求由1-n的最大流。並直到系統內無法再加入增廣路徑為止。

第一中演算法:Ford-Fulkerson演算法

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x3f3f3f3f
using namespace std;
int maper[205][205],pre[205];
int e_num,v_num;
queue<int>fp;
bool bfs(int src,int des)
{
         int index,i;
         memset(pre,-1,sizeof(pre));
         while(!fp.empty())fp.pop();
         pre[src]=src;
         fp.push(src);
         while(!fp.empty())
         {
                  index=fp.front();
                  fp.pop();
                  for(i=1;i<=v_num;i++)
                  {
                         if(pre[i]==-1&&maper[index][i]>0)
                         {
                                   pre[i]=index;
                                   fp.push(i);
                                   if(i==des)return true;
                         }
                  }
         }                                              //尋找增廣路徑
         return false;
}
int maxflow(int src,int des)
{
        int i,jieguo=0,minflow;
        while(bfs(src,des))
        {
                minflow=INF;
                for(i=des;i!=src;i=pre[i])
                       minflow=min(minflow,maper[pre[i]][i]);
                for(i=des;i!=src;i=pre[i])
                {
                        maper[pre[i]][i]-=minflow;
                        maper[i][pre[i]]+=minflow;
                }
                jieguo+=minflow;
        }
        return jieguo;
}
int main()
{
        //freopen("input","r",stdin);
        int i;
        int u,v,w;
        while(scanf("%d %d",&e_num,&v_num)!=EOF)
        {
                  memset(maper,0,sizeof(maper));
                  for(i=1;i<=e_num;i++)
                  {
                           cin >> u >> v >> w;
                           maper[u][v]+=w;
                  }
                  int ans=maxflow(1,v_num);
                  cout << ans << endl;
        }
        return 0;
}

第二種演算法:Dinic演算法:首先用BFS對整個圖中的節點進行分層(按照搜尋到達的前後順序)。然後利用DFS對找到過的增廣路徑進行擴充套件並更新網路流。然後再次進行分層,增廣。進過迭代後,如果BFS無法到底匯點,則說明不存在從源點到匯點的增廣路徑。搜尋即告結束。此時我們得到的流一定為最大流。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define INF 0x3f3f3f3f
#define V 205
using namespace std;
int matcher[V][V], e_num, v_num;
int src,des,height[V];
queue<int>myrode;
bool bfs(int src, int des)
{
         int i;
         for(i=1;i<=v_num;i++)height[i] = -1;
         while(!myrode.empty())myrode.pop();
         myrode.push(src);height[src]=0;
         while(!myrode.empty())
         {
                  int index = myrode.front();
                  myrode.pop();
                  for(i = 1;i <= v_num; i++)
                  {
                            if(height[i] == -1&& matcher[index][i] > 0)
                            {
                                      height[i]=height[index] + 1;
                                      myrode.push(i);
                            }
                  }
         }
         if(height[des] == -1)return false;
         else return true;
}                        //利用廣度搜索將整個圖分層

int dinic( int n, int contain)
{
        if(n==des)return contain;//廣度搜索達到了匯點,直接返回
        int  i , temp, last;
        temp = contain;
        for(i=1;i<=v_num;i++)
        {
               if(height[i] == height[n]+1&&matcher[n][i]>0)
               {
                       last = dinic(i,min(contain, matcher[n][i]));
                       contain -= last;
                       matcher[n][i]-=last;
                       matcher[i][n]+=last;
               }
               if(contain<=0)break;//優化:當正向流量用盡時,不再繼續搜尋
        }
        return temp-contain;//返回所用的最大流
}

int main()
{
        freopen("input","r",stdin);
        int  i,  u, v, w, ans;
        while(scanf("%d %d",&e_num,&v_num)!=EOF)
        {
                  memset(matcher,0,sizeof(matcher));
                  ans = 0;
                  for(i = 1;i <= e_num; i++)
                  {
                          cin >> u >> v >> w;
                          matcher[u][v] += w;
                  }
                  src = 1;des =  v_num;
                  while(bfs(src , des))
                  {
                            ans += dinic(src, INF);
                  }
                  cout << ans << endl;
        }
        return 0;
}

第三種方法:推送-重貼標籤方法.這是演算法導論上介紹的一種方法。首先,我們構造一條預流,從源點引出的每個管道都是滿載的。那麼,與源點相連線的點都會滿溢。此時,我們構造一個height陣列記錄每個點的高度。如果一個點比其他所有的點高度都低且處於滿溢的狀態時,我們就提高他的高度讓多餘的資源流出,這樣的操作稱為(重貼標籤),然後,滿溢的液體流出到height較低的地方,我們稱為推送。當沒有點滿足推送和重貼標籤的條件時,計算結束,我們得到的流即是一個最大流。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define INF 0x3f3f3f3f
#define V 205
using namespace std;
int height[V],over[V];
int matcher[V][V], e_num, v_num;
int src,des;
queue<int>lister;
int push_rebel(int s,int t)
{
       int jieguo=0;

       while(!lister.empty())lister.pop();
       memset(height,0,sizeof(height));
       memset(over,0,sizeof(over));
       over[s]=INF;over[t]=-INF;
       height[s]=v_num;
       lister.push(s);

       int index,temp,i;
       while(!lister.empty())
       {
               index = lister.front();
               lister.pop();
               for(i=1;i<=v_num;i++)
               {
                        temp = min(over[index],matcher[index][i]);
                        if(temp>0&&(height[index]==height[i]+1|| index == s))//檢查是否滿足push操作
                        {
                                 matcher[index][i] -= temp;
                                 matcher[i][index] += temp;
                                 if(i==t)jieguo += temp;
                                 over[index] -= temp;over[i] += temp;
                                 if(i!=s&&i!=t)lister.push(i);//若i非源點和匯點,則壓入佇列
                        }
                        if(over[index]<=0)break;
               }
               if(index!=s&&index!=t&&over[index]>0)
               {
                       lister.push(index);
                       height[index]++;
               }//若index依然滿溢,則增加index點的高度
       }
       return jieguo;
}
int main()
{
        freopen("input","r",stdin);
        int  i,  u, v, w, ans;
        while(scanf("%d %d",&e_num,&v_num)!=EOF)
        {
                  memset(matcher,0,sizeof(matcher));
                  ans = 0;
                  for(i = 1;i <= e_num; i++)
                  {
                          cin >> u >> v >> w;
                          matcher[u][v] += w;
                  }
                  src = 1;des =  v_num;
                  ans = push_rebel(src, des);
                  cout << ans << endl;

        }
        return 0;
}



相關推薦

[USACO15DEC]Max Flow樹鏈剖分,線段樹

FJ給他的牛棚的N(2≤N≤50,000)個隔間之間安裝了N-1根管道,隔間編號從1到N。所有隔間都被管道連通了。 FJ有K(1≤K≤100,000)條運輸牛奶的路線,第i條路線從隔間si運輸到隔間ti。一條運輸路線會給它的兩個端點處的隔間以及中間途徑的所有隔間帶來一個單位的運輸壓力,你需要計算壓力最大的隔

網絡初步:<>——核心增廣路算法

dfs space 10000+ can style 最大 strong names using 終於開始接觸網絡流了; 網絡流到底是個蝦米東東,用比較學術的話說,就是 一個有向圖 G=(V,E); 有兩個特別的點:源點s、匯點t; 圖中每條邊(u,v)

模板 EK 鄰接表

題目描述 如題,給出一個網路圖,以及其源點和匯點,求出其網路最大流。 輸入輸出格式 輸入格式: 第一行包含四個正整數N、M、S、T,分別表示點的個數、有向邊的個數、源點序號、匯點序號。 接下來M行每行包含三個正整數ui、vi、wi,表示第i條有向邊從ui出發,到

【USACO15DEC】Max Flow樹上差分

聽了教練的考前須知 蒟蒻緊張的要死 只想做信心題 #include<bits/stdc++.h> #define N 50005 using namespace std; int n,k,tot,first[N]; struct Tree { int to,next; }edge[2*N

問題講解Lingo

第一節 圖論的基本知識 1. 圖的概念 定義 圖G(V,E)是指一個二元組(V(G),E(G)),其中: (1)V(G)={v1,v2,…, vn}是非空有限集,稱為頂點集, (2)E(G)是

基本演算法ff演算法&&dinic演算法&&push-rebeal演算法poj1273

最大流的基本概念有以下幾點:               1.殘存網路:即為一條管道被佔用了一部分流量之後所剩下的流量。在網路流中,圖被看為一個有向圖,殘存流量向量相加後永遠不變。這一點有點像基爾霍夫定律。               2.在找到一個流之後,仍然存在的從源點

問題預推進演算法基本

/* Name: 最大流問題預流推進演算法 Copyright: Author: 巧若拙 Date: 14-06-17 09:26 Description: 最基本的預流推進演算法,沒有任何優化,每次遍歷所有的結點,找出活結點, 尋找可行弧,並預

教你徹底理解網路基本概念與演算法 小割

一.網路流:流&網路&割 1.網路流問題(NetWork Flow Problem): 給定指定的一個有向圖,其中有兩個特殊的點源S(Sources)和匯T(Sinks),每條邊有指定的容量(Capacity),求滿足條件的從S到T的最大流(Max

poj 1459 Power Network 初級->圖演算法->基本演算法:增廣路

Time Limit: 2000MS Memory Limit: 32768K Total Submissions: 19197 Accepted: 10125 Description A power network consists of nodes (pow

洛谷 P2740 [USACO4.2]草地排水Drainage Ditches EK增廣路演算法模板

題目:草地排水 思路:EK增廣路演算法求最大流模板 程式碼: #include<bits/stdc++.h> using namespace std; #define maxn

FF問題演算法

一、最大流問題 最大流問題(maximum flow problem),一種組合最優化問題,就是要討論如何充分利用裝置的能力,使得運輸的流量最大,以取得最好的效果。 實際來源: 有一個自來水管道運輸系統,起點是 s,終點是 t,途中經過的管道都有一個最大的容量,可以想象每條管道不

網路Dinic演算法

程式碼對應於 POJ - 3281 #include <iostream> #include <cstring> #include <cstdio> #include <queue> #define fuck

之Ford-Fulkerson演算法C++實現

本文主要講解最大流問題的Ford-Fulkerson解法。可是說這是一種方法,而不是演算法,因為它包含具有不同執行時間的幾種實現。該方法依賴於三種重要思想:殘留網路,增廣路徑和割。 一、殘留網路 顧名思義,殘留網路是指給定網路和一個流,其對應還可以容納的流組成的網路。具體說來,就是假定一個網

ADA演算法知識Ford-Fulkerson algorithm小割問題

Ford-Fulkerson algorithm 最大流演算法,用於計算流網路中的最大流量 Maximum flow minimum cut theorem  最大流最小割問題 [Traffic Problem] You got re-elected as the Mayor

經典的POJ1273網路裸題Dinic演算法POJ1273 【 & 當前弧優化 & 】

http://poj.org/problem?id=1273   Drainage Ditches Time Limit: 1000MS   Memory Limit: 10000K

【圖割】/小割演算法詳解Yuri Boykov and Vladimir Kolmogorov,2004

最大流/最小割(Max-Flow/Min-Cut)在解決計算機視覺中的能量方程最小化問題的強大,最早發現是Greig於1989年發表的文章:Exact Maximum A Posteriori Estimation for Binary Images。 最大流最小割演算法求解的能量方程,通常是基於圖結構

網路演算法EdmondsKarp

求網路流有很多演算法,這幾天學習了兩種,記錄一下EK演算法。 首先是網路流中的一些定義: V表示整個圖中的所有結點的集合.E表示整個圖中所有邊的集合.G = (V,E) ,表示整個圖.s表示網路的源點

POJ 2195-Going HomeKM演算法/小費用演算法

Going Home Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 21730 Accepted: 10990 Description On a grid map there are n

演算法導論》筆記18 含部分習題

流網路,容量值,源結點,匯點,容量限制,流量守恆。反平行,超級源結點,超級匯點。 Ford-Fulkerson方法。殘存網路,增廣路徑,最小切割定理。f是最大流,殘存網路不包含增廣路徑,|f|等於最小切割容量三者等價。 基本的Ford-Fulkerson演算法。Edmond

圖論Edmond Karp演算法

Edmond Karp演算法的大概思想: 反覆尋找源點s到匯點t之間的增廣路徑,若有,找出增廣路徑上每一段[容量-流量]的最小值delta,若無,則結束。 在尋找增廣路徑時,可以用BFS來找,並且更新殘留網路的值(涉及到反向邊)。 而找到delta後,則使最