最大流的理解以及dinic模板 poj1273

增廣路以及殘留網絡的定義不再贅述了。算導上說的很清楚,證明也有,看懂了就知道怎麼求最大流了。
而算導上提到的FF方法以及ek算法的僞代碼中都是將流與殘留容量分開儲存,其實代碼實現的時候我們只需存正反向弧的殘留容量即可。
然後是對殘留網絡的一些理解,殘留網絡中的反向弧是怎麼來的?
殘留網絡的每條邊都是這條有向邊的殘留容量,而殘留容量又由公式cf(u,v)=c(u,v)-f(u,v)得到,那麼對於一條不存在的有向邊(v,u),其容量c(v,u)=0,f(v,u)=-f(u,v)通過反對稱性可知,那麼這條不存在的有向邊的殘留容量就等於f(u,v).
而對於(v,u)來說,負的流是允許的,它滿足流≤容量的條件。而負的流的含義則是可以壓入f(u,v)個單位的流來抵消(u,v)對(v,u)的影響,然後還可壓入額外的c(v,u),也就是說一條正向弧的流給反向弧帶來的影響是給了反向弧更多的殘留容量,甚至是從沒有到有,那麼這個殘留流量的用途就是使流的方向更多樣,甚至說它使本來不可以走的路現在變得可以走了,因爲你每次找的都是增廣路上的最小殘留容量,正向弧壓入的流給反向弧帶來的殘留容量,這時就給了你反悔的機會,給運送員帶來更多的運送途徑來達到最大流的目的。
下面的例子:
在這幅圖中我們首先要增廣1->2->4->6,這時可以獲得一個容量爲2的流,但是如果不建立4->2反向弧的話,則無法進一 步增廣,最終答案爲2,顯然是不對的,然而如果建立了反向弧4->2,則第二次能進行 1->3->4->2->5->6的增廣,最大流爲3.
最後模板:
poj1273
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;

const int maxn=250;

struct node{
    int u,v,next,c;
};
node edge[maxn<<1];
int head[maxn];
int cnt;
int dis[maxn];
int n,m;
int ans;


void init(){
    memset(head,-1,sizeof(head));
    cnt=0;
    memset(dis,-1,sizeof(dis));
    ans=0;
}

void add(int a,int b,int c){
    edge[cnt].u=a;
    edge[cnt].v=b;
    edge[cnt].c=c;
    edge[cnt].next=head[a];
    head[a]=cnt++;
}

int bfs()// 給各點分層,離源點的遠近分
{
 memset(dis, -1, sizeof(dis));
 queue<int> q;
 dis[1] = 0;
 q.push(1);
 int i;
 int cur;
 while(!q.empty())
 {
  cur = q.front();
  q.pop();
  for(i = head[cur]; i != -1; i = edge[i].next)
  {
   if(dis[edge[i].v] == -1 && edge[i].c > 0)
   {
    dis[edge[i].v] = dis[cur] + 1;
    q.push(edge[i].v);
   }
  }
 }
 if(dis[m] < 0)
  return 0;
 return 1;
}

int Find(int x,int low){//找增廣
    int a;
    if(x==m) return low;
    for(int i=head[x];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(dis[v]==dis[x]+1 && edge[i].c>0 &&(a=Find(v,min(low,edge[i].c))))
        {
            edge[i].c -=a;
            edge[i^1].c +=a;
            return a;
        }
    }
    return 0;
}

void dinic(){
    int temp;
    while(bfs()){
//        printf("%d\n",tmp);
//        if(tmp==0) break;
        temp=Find(1,0x3f3f3f3f);
         ans+=temp;
    }
    printf("%d\n",ans);
}

int main(){
while(~scanf("%d%d",&n,&m)){
    int a,b,flow;
    init();
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&a,&b,&flow);
        add(a,b,flow);
        add(b,a,0);
    }
    dinic();
}
return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章