网络流Word格式.docx
《网络流Word格式.docx》由会员分享,可在线阅读,更多相关《网络流Word格式.docx(16页珍藏版)》请在冰豆网上搜索。
vardelta:
longint;
begin
delta:
=maxlongint;
k:
=n;
whilepre[k]<
>
-1do
=min(delta,c[pre[k],k]);
=pre[k];
end;
inc(maxflow,delta);
dec(c[pre[k],k],delta);
inc(c[k,pre[k]],delta);
2.深度优先搜索或宽度优先搜索寻找增广轨(时间复杂度O(V^2*E))。
【深度优先搜索的参考过程】
functionfind(k:
longint):
boolean;
vari:
integer;
ifk=nthenexit(true);
fori:
=1tondo
ifc[k,i]>
0then
pre[i]:
=k;
iffind(i)thenexit(true);
exit(false);
3.最短增广路算法(SAP:
ShortestAugmentingPathAlgorithm)(时间复杂度O(V*E^2))。
基本思想是:
依次通过标号差为1的结点找增广轨,以保证找到的增广路是当前最短的。
如果标号出现断链,则需要进行调整来维持。
如果c[i,j]>
0且d[i]-d[j]=1那么<
i,j>
叫允许弧,先从汇点出发宽度遍历所有结点,求出所有结点到汇点所经过的得最少路径数,用宽搜实现。
procedureSAP;
varpre:
array[0..maxn+1]oflongint;
i:
=1;
whiled[i]<
ndo
find:
=false;
forj:
ifc[i,j]>
=true;
pre[j]:
=i;
=j;
break;
iffindthen//找到允许弧,继续寻找
ifi=nthen
track_back;
//到达汇点,路径完整,求这条路上的最大流
continue;
d[i]:
=maxint;
//如果没找到允许弧,调整位与之相邻的最小的d[j]+1
if(c[i,j]>
0)and(d[i]>
d[j]+1)thend[i]:
=d[j]+1;
ifi<
1theni:
=pre[i];
4.SAP的间隙优化。
定义sum[k]为距离标号为k的结点数,在重标记过程中,当sum[k]减到0时,算法马上结束。
点i被重标记则其距离标号必然小于n。
而此时不存在此标号的顶点,则容许网络中必然不存在一条增广路径,因此算法结束。
这个优化使得算法效率显著提高。
第二节网络流例题解析
例16-1分配工作
【问题描述】
工厂有N个工人,一共需要做M种工作。
每个工人可以做一部分工作。
一项工作只能由一个人来做,而一个人最多只能做一项工作。
请你求出,最多有多少项工作可以被完成。
【输入】
第一行三个整数N,M,K。
接下来K行每行两个整数ai,bi,表示工人ai可以做工作bi。
【输出】
一个整数,表示可以完成的工作数量。
【输入样例】
333
11
21
33
【输出样例】
2
【分析】
若对于每个人与其可以加工的零件连一条权为一的边,之后从图外的一个源点对每个工人引一条边,从图外的一个汇点对每个工件引一条边。
求从源点到汇点的最大流即可求出工人与工件间最多同时存在的边数,亦即最多加工的工件数。
至此此题被转化为网络流问题,可以解决。
【参考程序】
var
map,max:
array[0..2001,0..2001]oflongint;
q,p:
array[0..2001]oflongint;
v:
array[0..2001]ofboolean;
n,m,i,j,k,e,s,a,b,sum:
functionbfs():
var
i,j,x:
begin
q[1]:
=0;
s:
e:
fori:
=1ton+m+1dov[i]:
v[0]:
repeat
inc(s);
x:
=q[s];
ifx=n+m+1thenexit(true);
=1ton+m+1do
if(max[x,i]-map[x,i]>
0)and(v[i]=false)thenbegin
inc(e);
ife>
2000thene:
q[e]:
p[e]:
=s;
v[i]:
end;
ifs>
2*(n+m)thenbreak;
2000thens:
untils=e;
exit(false);
readln(n,m,k);
=1tokdobegin
readln(a,b);
b:
=b+n;
max[a,b]:
max[b,a]:
=1tondobeginmax[0,i]:
max[i,0]:
=1tomdobeginmax[n+i,n+m+1]:
max[n+m+1,n+i]:
whilebfsdobegin
i:
inc(sum);
j:
=p[i];
inc(map[q[i],q[j]]);
dec(map[q[j],q[i]]);
untilp[i]=0;
writeln(sum);
end.
例16-2ditch
【题目来源:
USACOTraining4.2DrainageDitches】
在农夫约翰的农场上,每逢下雨,Bessie最喜欢的三叶草地就积聚了一潭水。
这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间。
因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水淹没的烦恼(不用担心,雨水会流向附近的一条小溪)。
作为一名一流的技师,农夫约翰已经在每条排水沟的一端安上了控制器,这样他可以控制流入排水沟的水流量。
农夫约翰知道每一条排水沟每分钟可以流过的水量,和排水系统的准确布局(起点为水潭而终点为小溪的一张网)。
需要注意的是,有些时候从一处到另一处不只有一条排水沟。
根据这些信息,计算从水潭排水到小溪的最大流量。
对于给出的每条排水沟,雨水只能沿着一个方向流动,注意可能会出现雨水环形流动的情形。
I【输入】
(fileditch.in)
第1行:
两个用空格分开的整数N(0<
=N<
=200)和M(2<
=M<
=200)。
N是农夫John已经挖好的排水沟的数量,M是排水沟交叉点的数量。
交点1是水潭,交点M是小溪。
第二行到第N+1行:
每行有三个整数,Si,Ei,和Ci。
Si和Ei(1<
=Si,Ei<
=M)指明排水沟两端的交点,雨水从Si流向Ei。
Ci(0<
=Ci<
=10,000,000)是这条排水沟的最大容量。
【输出】(fileditch.out)
输出一个整数,即排水的最大流量。
54
1240
1420
2420
2330
3410
【输出样例】
50
这个题是典型的最大流问题,由于数据规模很小,我们可以使用BFS找增广路。
每次找增广路的时候把汇能增广的流量加入到最大流中,直到无法增广为止。
programditch;
const
MXN=207;
n,m,s,t,i,u,v,w:
f,c:
array[1..MXN,1..MXN]oflongint;
pre,low,q:
array[1..MXN]oflongint;
vis:
array[1..MXN]ofboolean;
functionmaxflow:
flow,l,r,u,v:
flow:
fillchar(low,sizeof(low),0);
fillchar(vis,sizeof(vis),0);
vis[s]:
fillchar(q,sizeof(q),0);
low[s]:
q[1]:
l:
r:
=2;
whilel<
rdobegin
inc(l);
u:
=q[l];
forv:
ifnotvis[v]andc[u,v]>
f[u,v]thenbegin
vis[v]:
pre[v]:
=u;
inc(r);
q[r]:
=v;
low[v]:
=c[u,v]-f[u,v];
iflow[v]>
low[u]thenlow[v]:
=low[u];
end;
end;
iflow[t]>
0thenbegin
u:
=t;
repeat
f[pre[u],u]:
=f[pre[u],u]+low[t];
f[u,pre[u]]:
=f[u,pre[u]]-low[t];
u:
=pre[u];
untilu=s;
flow:
=flow+low[t];
untillow[t]=0;
exit(flow);
assign(input,"
ditch.in"
);
assign(output,"
ditch.out"
reset(input);
rewrite(output);
read(m,n);
t:
=1tomdobegin
read(u,v,w);
c[u,v]:
=c[u,v]+w;
writeln(maxflow);
close(input);
close(output);
例16-3K-联赛
K-联赛职业足球俱乐部的球迷们都是有组织的训练有素的啦啦队员,就像红魔啦啦队一样(2002年韩日世界杯上韩国队的啦啦队)。
这个赛季,经过很多场比赛以后,球迷们希望知道他们支持的球队是否还有机会赢得最后的联赛冠军。
换句话说,球队是否可以通过某种特定的比赛结果最终取得最高的积分(获胜场次最多)。
(允许出现多支队并列第一的情况。
)
现在,给出每个队的胜负场数,wi和di,分别表示teami的胜场和负场(1≤i≤n)。
还给出ai,j,表示teami和teamj之间还剩多少场比赛要进行(1≤i,j≤n)。
这里,n表示参加联赛的队数,所有的队分别用1,2,…,n来编号。
你的任务是找出所有还有可能获得冠军的球队。
所有队参加的比赛数是相同的,并且为了简化问题,你可以认为不存在平局(比赛结果只有胜或负两种)。
第一行一个整数n(1≤n≤25),表示联赛中的队数。
第二行2n个数,w1,d1,w2,d2,……,wn,dn,所有的数不超过100。
第3到n+2行每行n个数,第i+2行的n个数为ai,1,ai,2,…,ai,n。
所有的数都不超过10。
ai,j=aj,i,如果i=j,则ai,j=0。
若干行,输出所有可能获得冠军的球队,按其编号升序输出,每行一个。
3
201102
022
202
220
123
对于队伍i,如果存在时期总分最高的方案,那么显然至少存在一种队伍i剩下比赛全胜而最终总分最高的方案,因此先使得i的剩余比赛均获胜,之后因为其他队伍得分不能超过i,而每场比赛都必须决出胜负。
对此,可以构图,对于a,b的一场比赛,从a向a`,b`各引一条容量为一的边,从一个源向所有a引容量无限的边,之后根据各队不同情况确定各a`到汇的边的容量,求出最大流即是最多可以决出胜负的场数,显然地,只有当此场数等于比赛总数时,i才可以夺冠。
map,m:
array[0..50,0..51]oflongint;
a:
array[1..25,1..25]oflongint;
w:
array[1..25]oflongint;
array[0..51]ofboolean;
q,pre,t:
array[0..52]oflongint;
n,i,j,k,l,r,x,h,sum,max,flow:
functionmin(a,b:
ifa<
bthenexit(a)
elseexit(b);
readln(n);
=1tondoread(w[i],x);
forj:
=1tondobegin
read(a[i,j]);
ifi<
jthenbegin
inc(sum,a[i,j]);
inc(map[i,j+n],a[i,j]);
inc(map[0,i],a[i,j]);
t[0]:
pre[0]:
=-1;
h:
=n*2+1;
fork:
m:
=map;
max:
=w[k];
inc(max,a[i,k]);
kthendec(m[0,i],a[i,k]);
m[0,k]:
m[i+n,h]:
=max-a[i,k];
l:
r:
fillchar(v,sizeof(v),false);
inc(l);
=1tohdo
if(notv[i])and(m[q[l],i]>
0)thenbegin
pre[i]:
t[i]:
=min(t[q[l]],m[q[l],i]);
inc(r);
q[r]:
ifv[h]thenbreak;
untill=r;
ifv[h]thenbegin
=h;
inc(flow,t[h]);
whilepre[r]<
-1dobegin
dec(m[pre[r],r],t[h]);
inc(m[r,pre[r]],t[h]);
=pre[r];
untilnot(v[h]);
ifsum-max+w[k]=flowthenwriteln(k);
例16-4破坏石油运输系统问题
【题目来源:
RQNOJP306】
【问题描述】
某组织打算摧毁发烂稀国的石油运输系统。
该系统可以看成一个运输网络,由许多结点和连接结点的管道组成。
只有地点A生产石油,生产的石油通过管道运输到地点B,石油不能在中间点累积。
管道是双向的,每条管道连接两个不同的结点,每两个结点之间只有一条管道连接。
每条管道有一个抗压指数,当石油的流量超过这个数管道就会爆炸。
A地生产石油的速度是很快的,但由于抗压指数的问题,能运到B的有一个上限。
发烂稀国比较贪婪,他们采用了使他们获得最多石油的运输方案。
某组织有一个特殊的物质,能使一条管道的抗压指数下降1。
作为该组织的首席程序员,你的任务就是告诉领导,让那些管道的抗压指数下降,一定可以摧毁发烂稀国的石油运输网络。
第1行包含四个整数n,m,s,t,表示有n个结点(编号为1,2,3,……,n),m条管道,s和t分别是A地和B地的编号。
2<
=n<
=130,0<
=m<
=n(n-1)/2,1<
=s,t<
=n。
接下来m行,每行描述一条管道,包含3个整数i,j,c。
i,j分别为管道连接的2个结点。
C为该条管道的抗压指数。
1<
=i,j<
=n,1<
=c<
=10000。
【输出】
第1行输出抗压指数减少1就爆炸的管道的条数k。
接下来k行每行输出一个整数p(1<
=p<
=m),说明第p条管道如果抗压指数减少1就必定爆炸。
序号p按照管道输入的顺序,并按照p的升序输出。
【输入样例】
4414
24100
121
31100
431
【输出样例】
4
这道题目不难看出是一道网络流的题目,我们可以先求出当前情况下的最大流,然后对所有满流边进行减1,然后再求最大流,如果当前最大流小于先前最大流,这条边一定不是必要边,反之一定是一条必要边。
programrqnoj306;
constMXN=140;
g,c,f:
array[1..MXN,1..MXN]oflongint;
d,vd:
array[0..MXN]oflongint;
dx,dy,a,db:
array[1..20000]oflongint;
i,j,n,m,ans,tmp,s,t,x,y,v,useedge:
functionmin(a,b:
ifa>
bthenexit(b)elseexit(a);
functiondfs(u,flow:
v,tmp,ans:
if(u=t)thenexit(flow);
ans:
forv:
=1tondoif(g[u][v]>
0)and(d[u]-1=d[v])then
tmp:
=dfs(v,min(flow-ans,g[u][v]));
dec(g[u][v],tmp);
inc(g[v][u],tmp);
if(c[u][v]>
0)theninc(f[u][v],tmp)elseinc(f[v][u],tmp);
inc(ans,tmp);
if(ans=flow)thenexit(ans);
if(d[s]>
=n)thenexit(ans);
dec(vd[d[u]]);
if(vd[d[u]]=0)thend[s]:
inc(d[u]);
inc(vd[d[u]]);
exit(ans);
functionsap():
ans,i,j:
vd[0]:
=1ton-1dovd[i]:
=1tondod[i]:
g[i][j]:
=c[i][j];
f[i][j]:
while(d[s]<
n)do
inc(ans,dfs(s,maxlongint));
exit(ans);
readln(n,m,s,t);
=1tomdo
begin
readln(x,y,v);
dx[i]:
=x;
dy[i]:
=y;
inc(c[x][y],v);
inc(c[y][x],v);
=sap();
j:
useedge:
=1tomdoif((f[dy[i]][dx[i]]=c[dy[i]][dx[