网络流题目
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
[PKU 3281]Dining(构图+网络流)
题目大意】
就是有n个牛,有f种食物和d种饮料,每个牛喜欢一个或多个食物和饮料,但是所有的食物和饮料每种都只有一个,问最多可以满足多少头牛的需要。
【题目分析】
其实这个是很简单的,很明显的网络流模型,构图方法是把一头牛拆成两个点,两边分别是食物和饮料,然后把食物和左面的那一排牛连接在一起,右面的那一排牛和饮料连接在一起,两头牛拆开的点之间再连一条边。
加上超级源点和所有食物相连,所有饮料和超级汇点相连。
所有边上的容量都是1。
然后求最大流就可以了。
【代码(P.S.一次AC,HOHO~)】:
program PKU_3281;
var
n,f,d,x,y,i,j,p,nn,s,t,delta,min,minj,tot:longint;
g:array[0..401,0..401] of longint;
dis,his,vh,di,pre:array[0..402] of longint;
flag:boolean;
begin
assign(input,'a.in');
assign(output,'a.out');
reset(input); rewrite(output);
readln(n,f,d);
for i:=1 to n do
begin
read(x,y);
for j:=1 to x do
begin
read(p);
g[p,f+i]:=maxlongint;
end;
for j:=1 to y do
begin
read(p);
g[f+n+i,f+2*n+p]:=maxlongint;
end;
g[f+i,f+n+i]:=1;
end;
for i:=1 to f do
g[0,i]:=1;
for i:=1 to d do
g[f+2*n+i,f+2*n+d+1]:=1;
nn:=f+2*n+d+1;
vh[0]:=nn+1;
for i:=0 to nn do di[i]:=0;
s:=0; t:=nn;
i:=s; delta:=maxlongint; tot:=0;
while dis[s]0) and (dis[j]+1=dis[i]) then begin
flag:=true;
pre[j]:=i;
di[i]:=j;
if g[i,j]<delta then delta:=g[i,j];
i:=j;
if i=t then
begin
inc(tot,delta);
x:=t; y:=pre[x];
while xs do
begin
dec(g[y,x],delta);
inc(g[x,y],delta);
x:=pre[x]; y:=pre[y];
end;
i:=s; delta:=maxlongint;
end;
break;
end;
if flag then continue;
min:=nn;
for j:=0 to nn do
if (g[i,j]>0) and (min>dis[j]) then
begin
min:=dis[j];
minj:=j;
end;
di[i]:=minj;
dec(vh[dis[i]]);
if vh[dis[i]]=0 then break;
dis[i]:=min+1;
inc(vh[dis[i]]);
if is then
begin
i:=pre[i];
delta:=his[i];
end;
end;
writeln(tot);
close(input); close(output);
end.
[PKU 1149]PIGS(网络流+构图)
题目描述:
说有一个人有好几猪圈的猪,给你猪圈中猪的个数。
这个人自己没有猪圈的钥匙。
现在他知道有一些顾客要来买猪,他们会带来一些猪圈的钥匙。
这样他就可以打开猪圈并卖给顾客猪,在这过程中他可以调换这几圈猪中的猪。
问你他最多可以卖出多少猪……
分析:
这个题本来不太好想到网络流,但是如果告诉你这个是网络流的题,你也会找出一个最原始的网络流模型。
但是我们发现这个图极其巨大,任何的网络流算法都无法处理,所以要像一种好的构图方法。
给大家一个地址,这里的讲解写的很好:
/post.2059102.html
看到namiheike大牛blog上的一句话:“在面对网络流问题时,如果一时想不出很好的构图方法,不如先构造一个最直观,或者说最“硬来”的模型,然后再用合并节点和边的方法来简直化这个模型。
经过简化以后,好的构图思路自然就会涌现出来了。
这是解决网络流问题的一个好方法。
”很直观也很好的方法~
第一次在实际问题上写SAP,贴代码以示纪念(P.S.这个0ms的代码成功刷进Status第一版):
program PKU_1149;
const
maxn=10000000;
var
g:array[0..101,0..101] of longint;
num,dis,vh,pre,di,his:array[0..102] of longint;
pigs:array[1..1000] of longint;
key:array[1..1000,0..100] of longint;
m,n,i,j,k,x,s,t,delta,tot,y,min,minj:longint;
flag:boolean;
function min2(x,y:longint):longint;
begin
if x0) then
begin
inc(g[0,key[i,1]],pigs[i]);
g[key[i,1],n+1]:=num[key[i,1]];
for j:=2 to key[i,0] do
begin
g[key[i,j-1],key[i,j]]:=maxlongint;
g[key[i,j],n+1]:=num[key[i,j]];
end;
end;
fillchar(dis,sizeof(dis),0);
fillchar(vh,sizeof(vh),0);
fillchar(pre,sizeof(pre),0);
s:=0; t:=n+1;
vh[0]:=n+2;
for i:=0 to n+1 do di[i]:=0;
i:=s; delta:=maxlongint; tot:=0;
while dis[s]0) and (dis[j]+1=dis[i]) then begin
flag:=true;
pre[j]:=i;
delta:=min2(delta,g[i,j]);
di[i]:=j;
i:=j;
if i=t then
begin
inc(tot,delta);
x:=t; y:=pre[x];
while xs do
begin
dec(g[y,x],delta);
inc(g[x,y],delta);
x:=pre[x]; y:=pre[y];
end;
i:=s; delta:=maxlongint;
end;
break;
end;
if flag then continue;
min:=n;
for j:=0 to n+1 do
if (g[i,j]>0) and (min>dis[j]) then
begin
minj:=j;
min:=dis[j];
end;
di[i]:=minj;
dec(vh[dis[i]]);
if vh[dis[i]]=0 then break;
dis[i]:=min+1;
inc(vh[dis[i]]);
if is then
begin i:=pre[i]; delta:=his[i]; end; end;
writeln(tot);
close(input); close(output);
end.。