//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算法的思想是为了减少增广次数,建立一个辅助网络L,L与原网络G具有相同的节点数,但边上的容量有所不同,在L上进行增广,将增广后的流值回写到原网络上,再建立当前网络的辅助网络,如此反复,达到最大流。分层的目的是降低寻找增广路的代价。
算法步骤如下:
STEP1:建造原网络G的一个分层网络L。
STEP2:用增广路算法计算L的最大流F,若在L中找不到增广路,算法结束。
SETP3:根据F更新G中的流f,转STEP1。
分层网络的构造算法:
STEP1:标号源节点s,M[s]=0。
STEP2:调用广度优先遍历算法,执行一步遍历操作,当前遍历的弧e=v1v2,令r=G.u(e)-G.f(e)。
若r>0,则
(1) 若M[v2]还没有遍历,则M[v2]=M[v1]+1,且将弧e加入到L中,容量L.u(e)=r。
(2) 若M[v2]已经遍历且M[v2]=M[v1]+1,则将边e加入到L中,容量L.u(e)=r。
(3) 否则L.u(e)=0。
否则L.u(e)=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