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

10 篇文章 0 订阅

题意: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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值