您的位置:首页 > 其它

bzoj 1532 二分答案+最大流判断

2017-03-05 17:08 288 查看
题意:n个人,m场比赛,求赢得最多的人最少赢几场

妥妥的二分答案,然后建图判一下最大流是否等于比赛场数

建图:S -> 每个人(编号为i)边权为mid       (表示每个人最多赢mid场)

           每个人(编号为i) -> 参加的第j场比赛(编号为n+j)边权为1

           每场比赛(编号为n+j) -> T 边权为1  (表示每场比赛最多有一个人赢)

type
rec=record
a,b:longint;
end;

var
n,m,x,ans,y,l :longint;
ll,rr,mid,ss,st :longint;
i :longint;
pre,other,len :array[0..100010] of longint;
game :array[0..10010] of rec;
last,dis,que :array[0..20010] of longint;
function min(a,b:longint):longint;
begin
if a<b then exit(a) else exit(b);
end;

procedure connect(x,y,z:longint);
begin
inc(l);
pre[l]:=last[x];
last[x]:=l;
other[l]:=y;
len[l]:=z;
end;

function bfs:boolean;
var
i,h,tl,cur,p,q:longint;
begin
for i:=1 to st do dis[i]:=0;
h:=0; tl:=1; que[1]:=ss; dis[ss]:=1;
while (h<>tl) do
begin
h:=h mod 20005+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 20005+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
rest,tt,p,q: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(len[q],rest));
dec(len[q],tt);
inc(len[q xor 1],tt);
dec(rest,tt);
if rest=0 then exit(flow);
end;
q:=pre[q];
end;
if rest=flow then dis[x]:=0;
exit(flow-rest);
end;

function check(x:longint):boolean;
var
i:longint;
tt:longint;
begin
fillchar(last,sizeof(last),0); l:=1; tt:=0;
for i:=1 to m do
begin
connect(game[i].a,n+i,1);
connect(n+i,game[i].a,0);
connect(game[i].b,n+i,1);
connect(n+i,game[i].b,0);
end;
for i:=n+1 to n+m do
begin
connect(i,st,1);
connect(st,i,0);
end;
for i:=1 to n do
begin
connect(ss,i,x);
connect(i,ss,0);
end;
while bfs do inc(tt,dinic(ss,maxlongint div 10));
if tt=m then exit(true) else exit(false);
end;

begin
read(n,m);
for i:=1 to m do read(game[i].a,game[i].b);
ss:=n+m+1; st:=ss+1;
ll:=1; rr:=m; ans:=maxlongint;
while (ll<=rr) do
begin
mid:=(ll+rr)>>1;
if check(mid) then
begin
if mid<ans then ans:=mid; rr:=mid-1;
end else ll:=mid+1;
end;
writeln(ans);
end.
——by Eirlys



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bzoj