Milking Order

Milking Order

题意:给出m个描述状态,其中包含若干个边的关系,问最多能取x (x<=m)个状态,使得形成的图没有环。就是说取x个状态,用状态中的关系建边,其中不能有环。

题解:最大化x?和二分答案有点关系。所以首先要二分x,判断是否有环。这个可以用拓扑或者tarjan。我用的是拓扑,判环的依据是队尾t是否等于n,如果不等于n,则一定有环。(只有入度等于1才进队)于是操作就有点复杂了,(我会在程序里标记)。最后因为要字典序最小,要用堆来输出答案。

  1 var
  2 q,head,next,rd,a,b,id,ans,f:array[0..500005]of longint;
  3 e,i,j,mid,x,y,z,l,r,t,len,n,k,tot,m:longint;
  4 procedure add(x,y:longint);
  5  begin
  6   inc(e);next[e]:=head[x];head[x]:=e; a[e]:=y;id[e]:=i;
  7  end;
  8  function check(mid:longint):boolean;
  9 
 10   var i,h,tail:longint;
 11    begin
 12    fillchar(rd,sizeof(rd),0);
 13    fillchar(q,sizeof(q),0);
 14    tail:=0; t:=0;
 15     for i:=1 to e do
 16      begin
 17        if id[i]<=mid then
 18          begin
 19            inc(rd[a[i]]);
 20          end;
 21      end;
 22   
 23  for i:=1 to n do
 24    if rd[i]=0 then
 25      begin
 26        inc(t);
 27        inc(tail);
 28        q[tail]:=i;
 29      end;
 30      if tail=0 then exit(false);
 31      h:=0;
 32      while h<tail do
 33       begin
 34          inc(h);
 35          i:=head[q[h]];
 36         while  (id[i]>mid)and(i>0) do begin i:=next[i];  end;// 判断边是否超过mid
 37 
 38            while (i>0) do
 39               begin
 40                dec(rd[a[i]]);
 41                if rd[a[i]]=0 then
 42                  begin
 43                    inc(t);inc(tail);q[tail]:=a[i];
 44                  // if mid =3 then  writeln(tail);
 45                  end;
 46                i:=next[i];
 47                while (i>0)and(id[i]>mid) do i:=next[i]; //同样判断
 48               end;
 49       end;
 50   
 51     if t=n then exit(true) else exit(false);
 52   end;
 53   procedure make(x:longint);
 54  var now,father,t:longint;
 55   begin
 56   inc(len);
 57   f[len]:=x;
 58   now:=len;
 59    while (now>1)and(f[now>>1]>f[now]) do
 60     begin
 61       father:=now>>1;
 62          t:=f[father];
 63          f[father]:=f[now];
 64          f[now]:=t;
 65          now:=father;
 66     end;
 67  end;
 68 
 69   function detele:longint;
 70   var fa,son,t:longint;
 71       ss:boolean;
 72    begin
 73    k:=f[1];
 74    f[1]:=f[len];
 75    dec(len);
 76    fa:=1;ss:=false;
 77     while ((fa*2<=len)or(fa*2+1<=len))and(not ss) do
 78      begin
 79          if (fa*2+1>len) or(f[fa*2]<f[fa*2+1]) then
 80          son:=fa*2  else son:=fa*2+1;
 81          if f[fa]>f[son] then
 82            begin
 83             t:=f[fa];
 84             f[fa]:=f[son];
 85             f[son]:=t;
 86           fa:=son;
 87       end
 88        else break;
 89   end;
 90  end;
 91 
 92 begin
 93 readln(n,m);
 94 for i:=1 to m do
 95  begin
 96    read(x);
 97    for j:=1 to x do
 98     begin
 99       read(y);
100       if j>1 then begin  add(z,y); end;
101       z:=y;
102     end;
103  end;
104 l:=0;r:=m;
105 while l<=r do//二分答案模板(
106  begin
107    mid:=(l+r) div 2;
108    //writeln(l,' ',r);
109    if check(mid) then l:=mid+1 else r:=mid-1;
110   
111  end;
112  l:=l-1;//直到这里)
113 
114    fillchar(rd,sizeof(rd),0);
115    for i:=1 to e do
116      begin
117        if id[i]<=l then
118          begin
119            inc(rd[a[i]]);
120          end;
121      end;
122     for i:=1 to n do
123       begin
124         if rd[i]=0 then make(i);//堆操作
125       end;
126      tot:=0;
127     while tot<n  do
128    begin
129      inc(tot);
130      detele;
131      write(k,' ');//堆操作
132       i:=head[k];
133       while (id[i]>l)and(i>0) do i:=next[i];//判断是否大于二分答案的最终答案
134 
135       while i>0 do
136         begin
137          dec(rd[a[i]]);
138          if rd[a[i]]=0 then make(a[i]);
139          i:=next[i];
140          while (i>0)and(id[i]>mid) do i:=next[i];//也需要判断
141         end;
142    end;
143 end.
NOIP2018 rp++
原文地址:https://www.cnblogs.com/brilliant107/p/9709650.html