题意:n头牛,m1种吃的,m3种喝的,每头牛有nm1种喜欢的吃的、nm2种喜欢的喝的,满足一头牛的条件是 :既给他一个爱吃的也给他一个爱喝的。(注意如果一头牛没有爱吃的或爱喝的,是永远不能满足的)。每种吃的和喝的能且只能用一次,求最多满足多少牛
最大流还是比较显然的,但是建图还是相当经(恶)典(心)的
给出正确的建图:
s -> 每种吃的 容量为1 (保证每种吃的能且只能用一次)
每种喝的 --> T 容量为1 (保证每种喝的能且只能用一次)
每头牛i拆点 i -> i' 容量为1 (保证每头牛只能满足一次)
第i头牛喜欢吃的 -> i 容量为1
i‘ - >’第i头牛喜欢喝的 容量为1
跑最大流即可
个人吐槽(屡战屡败的建图经历):
教练我要学建图QAQ
以下大雾
(1)第一个naive的建图
S -> 每头牛i 容量为1
每头牛 -> 爱吃的 容量为1
第i头牛爱吃的 -> 第i头牛爱喝的 容量为1
第i头牛爱喝的 -> T 容量为1
亲测:60分
虽然每种喝的保证最多用一次,每头牛最多满足一次
but,会出现一种情况:多头牛喜欢一种吃的,而同时又喜欢多种喝的,那么这种吃的会被重复使用,所以答案会大 orz
所以要严格限制吃的和喝的,就把吃的放源,喝的放汇,中间是牛,然后就有了第二个naive的图
(2)第二个naive的建图
S -> 每种吃的 容量为1
每种喝的 -> T 容量为1
第i头牛爱吃的 -> 第i头牛 容量为1
第i头牛 -> 第i头牛爱喝的 容量为1
虽然每种吃的和喝的都保证了最多用一次,
but,会出现一种情况:一头牛喜欢多种吃的和多种喝的,那么这头牛就是被多次满足记在答案中,所以答案会大 orz
所以要严格限制一头牛只被满足一次,就把牛拆点中间连1的容量来限流,这样才能保证牛也只被满足一次
感谢zzc为我这个深陷错误无法自拔的蒟蒻指出错误反例...
var
n,m1,m2,l,ss,st :longint;
last,dis,que :array[0..410] of longint;
nm1,nm2,ans,x :longint;
i,j :longint;
pre,other,len :array[0..21010] of longint;
function min(a,b:longint):longint;
begin
if atl) do
begin
h:=h mod 305+1;
cur:=que[h];
q:=last[cur];
while (q<>0) do
begin
p:=other[q];
if (dis[p]=0) and (len[q]>0) then
begin
dis[p]:=dis[cur]+1;
tl:=tl mod 305+1;
que[tl]:=p;
if p=st then exit(true);
end;
q:=pre[q];
end;
end;
exit(false);
end;
function dinic(x,flow:longint):longint;
var
p,q,tt,rest:longint;
begin
if x=st then exit(flow);
rest:=flow;
q:=last[x];
while (q<>0) do
begin
p:=other[q];
if (dis[p]=dis[x]+1) and (len[q]>0) and (rest>0) then
begin
tt:=dinic(p,min(rest,len[q]));
dec(len[q],tt);
dec(rest,tt);
inc(len[q xor 1],tt);
if rest=0 then exit(flow);
end;
q:=pre[q];
end;
if rest=flow then dis[x]:=0;
exit(flow-rest);
end;
begin
read(n,m1,m2);
ss:=2*n+m1+m2+1; st:=ss+1; l:=1;
for i:=1 to m1 do
begin
connect(ss,i,1);
connect(i,ss,0);
end;
for i:=1 to n do
begin
connect(m1+i,m1+n+i,1);
connect(m1+n+i,m1+i,0);
end;
for i:=1 to n do
begin
read(nm1,nm2);
for j:=1 to nm1 do
begin
read(x);
connect(x,m1+i,1);
connect(m1+i,x,0);
end;
for j:=1 to nm2 do
begin
read(x);
connect(m1+n+i,m1+2*n+x,1);
connect(m1+2*n+x,m1+n+i,0);
end;
end;
//
for i:=1 to m2 do
begin
connect(m1+2*n+i,st,1);
connect(st,m1+2*n+i,0);
end;
ans:=0;
while bfs do inc(ans,dinic(ss,maxlongint div 10));
writeln(ans);
end.
—— by Eirlys