dinic模板

//DINIC模板(网络流)
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#define M 210
#define INF 0x7f7f7f7f
using namespace std;
int to[M],next[M],head[M],cnt,ceng[M],que[M],w[M];
int n,m,start,end;
void add(int a,int b,int flow)
{
    to[cnt]=b,next[cnt]=head[a],w[cnt]=flow,head[a]=cnt++;
    to[cnt]=a,next[cnt]=head[b],w[cnt]=0,head[b]=cnt++;
}
void read()
{
    memset(head,-1,sizeof head);
    //memset(next,-1,sizeof next);
    scanf("%d%d",&m,&n);
    int a,b,flow;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a,&b,&flow);
        add(a,b,flow);
    }
    end=n,start=1;//起点 终点 
}
bool bfs()
{
    memset(ceng,-1,sizeof ceng);
    int h=1,t=2;
    ceng[start]=0;
    que[1]=start;
    while(h<t)
    {
        int sta=que[h++];
        for(int i=head[sta];~i;i=next[i])
            if(w[i]>0&&ceng[to[i]]<0)
            {
                ceng[to[i]]=ceng[sta]+1;
                que[t++]=to[i];
            }
    }
    return(ceng[end]!=-1);
}
int find(int x,int low)
{
    int tmp=0,result=0;
    if(x==end) return(low);
    for(int i=head[x];~i&&result<low;i=next[i])
        if(w[i]>0&&ceng[to[i]]==ceng[x]+1)
        {
            tmp=find(to[i],min(w[i],low-result));
            w[i]-=tmp;
            w[i^1]+=tmp;
            result+=tmp;
        }
    if(!result) ceng[x]=-1;
    return(result);
}
int dinic()
{
    int ans=0,tmp;
    while(bfs()) ans+=find(start,INF);
    return(ans);
}
int main()
{
    read();
    cout<<dinic();
    system("pause");
    return 0;
}

http://proverbs.diandian.com/post/2012-05-10/19982671

http://wenku.baidu.com/view/ce39e0b8fd0a79563c1e72f8.html

Dinic算法的思想是为了减少增广次数,建立一个辅助网络LL与原网络G具有相同的节点数,但边上的容量有所不同,在L上进行增广,将增广后的流值回写到原网络上,再建立当前网络的辅助网络,如此反复,达到最大流。分层的目的是降低寻找增广路的代价。

算法步骤如下:

STEP1:建造原网络G的一个分层网络L

STEP2:用增广路算法计算L的最大流F,若在L中找不到增广路,算法结束。

SETP3:根据F更新G中的流f,转STEP1

分层网络的构造算法:

STEP1:标号源节点sM[s]0

STEP2:调用广度优先遍历算法,执行一步遍历操作,当前遍历的弧e=v1v2,令rG.ue)-G.fe)。

                 若r>0,则

1)    若M[v2]还没有遍历,则M[v2]=M[v1]+1,且将弧e加入到L中,容量L.ue)=r

2)    若M[v2]已经遍历且M[v2]=M[v1]+1,则将边e加入到L中,容量L.ue)=r

3)    否则L.ue)=0

否则L.ue)=0

重复本步直至G遍历完。其中的G.u(e)G.f(e)L.u(e)分别表示图G中弧e的容量上界和当前流量,图L中弧e的容量上界。

 

下附程序 (邻接表的程序,希望看得懂)

Program zw_dinicc;

type

  o=record

   point,next,c:longint;

   end;

Var

i,j,k,p,n,m,head,tail,s,t,tot,a1,a2,a3,tot1,a4:longint;

h,l:array[1..55002]of longint;

first:array[1..55002]of longint;

e:array[1..310002] of o;

procedure add(a,b,c:longint);

begin

  e[tot1].point:=b; e[tot1].next:=first[a]; e[tot1].c:=c; first[a]:=tot1; inc(tot1);

end;

 

procedure init;

  var i,x,y,q:longint;

  begin

    tot1:=2;

    readln(n,m);

    for i:=m+2 to n+m+1 do

     begin

      read(a1);

      add(i,n+m+2,a1);

      add(n+m+2,i,0);

     end;

    for i:=2 to m+1 do

     begin

      read(a1,a2,a3);

      add(i,1+m+a1,65536000); add(1+m+a1,i,0);

      add(i,1+m+a2,65536000); add(1+m+a2,i,0);

      add(1,i,a3);add(i,1,0);

      inc(j,a3);

     end;

    n:=2+m+n;

 

    s:=1;

    t:=n;

  end;

//以上为建边,用的是残量网络

procedure bfs;{构建分层图,从原点开始广搜}

var

i,j,k,now:longint;

begin

  head:=1; tail:=1;   l[head]:=s; fillchar(h,sizeof(h),127); h[s]:=0;

  while head<= tail do

   begin

      now:=l[head];     inc(head);     k:=first[now];

      while k>0 do

      begin

      if (h[e[k].point]>n) and(e[k].c>0) then{如果可以流,且该点未被访问}

       begin

        h[e[k].point]:=h[now]+1;

        inc(tail);

        l[tail]:=e[k].point;

       end;

       k:=e[k].next;

      end;

   end;

end;

 

function dfs(now,low:longint):longint;{根据分层图增广,low表示到now为止最多可增广流量}

var

i,j,k,tmp:longint;

begin

  if now=t then exit(low);

  dfs:=0;  k:=first[now];

  while  k>0 do

    begin

    if (e[k].c>0)  and (h[e[k].point]=h[now]+1)   then{如果在分层图中符合限制}

     begin

     if e[k].c<low   then tmp:=dfs(e[k].point,e[k].c){寻找可接受的最大流量}

                     else tmp:=dfs(e[k].point,low);

     if tmp=0 then h[e[k].point]:=maxlongint shr 1;

     dec(low,tmp);{把可流量减去增广值}

     dec(e[k].c,tmp);

     inc(e[k xor 1].c,tmp);

     inc(dfs,tmp);

     if low=0 then break;{若无法再增广,退出}

     end;

     k:=e[k].next;

    end;  

end;

 

Procedure main;

begin

  bfs;

  while h[t]<n  do{如果在分层图中找得到汇点}

   begin   

    inc(tot,dfs(s,maxlongint));{根据分层图增广}

    bfs;{根据新的流量构建分层图}

   end;

end;

 

Begin

  init;

  main;

  writeln(j-tot);

End

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值