bzoj1143: [CTSC2008]祭祀river【最长反链】

  • 内容
  • 评论
  • 相关

题目点击这里


当然题目难度是削弱过的。。。CTSC的题目哪只有这种难度。。。

首先题目给出的是一个有向无环图,然后求的是最长的反链长度,也就是原图里一个最大的点集,点集内部任意两点没有路径连接。

首先最长反链可以转化为最小路径覆盖问题。

对于一个有向无环图来说,显然每一条路径上只能有一个点在最长反链的点集里面。而在某一个最小路径覆盖里面,每一条路径都有一个点在最长反链的点集里面。

证明其实不难啦~就是一个抽屉原理而已。。。

然后最小路径覆盖的方法就可以看看我之前写的网络流24题里面的第三题~


代码:

const
  maxe=50000;
  maxn=1000;
  inf=2147483647;
type
  edge=record
         x,y,next,op:longint;
       end;
var
  e:array[0..maxe]of edge;
  a,gap,dis,pre,cur:array[0..maxn]of longint;
  n,m,i,j,k,l,s,t,u,v,cap,flow,mf:longint;
  ee:array[1..maxn,1..maxn]of longint;
procedure adde(u,v,cap,cc:longint);
var
  i:longint;
begin
  inc(l);
  e[l].y:=cap;
  e[l].x:=v;
  e[l].next:=a[u];
  e[l].op:=l+1;
  a[u]:=l;
  inc(l);
  e[l].y:=cc;
  e[l].x:=u;
  e[l].op:=l-1;
  e[l].next:=a[v];
  a[v]:=l;
end;
function min(a,b:longint):longint;
begin
  if a<b then exit(a) else exit(b);
end;
procedure sap;
var
  i,j,k,now,p,pp,dist:longint;
  f:boolean;
begin
  fillchar(dis,sizeof(dis),0);
  fillchar(gap,sizeof(gap),0);
  for i:=s to t do cur[i]:=a[i];
  mf:=0;
  now:=s;
  gap[t]:=t;
  flow:=inf;
  while dis[s]<=t do
  begin
    if now=t then
    begin
      flow:=inf;
      i:=s;
      while i<>t do
      begin
        flow:=min(flow,e[cur[i]].y);
        i:=e[cur[i]].x;
      end;
      i:=s;
      while i<>t do
      begin
        dec(e[cur[i]].y,flow);
        inc(e[e[cur[i]].op].y,flow);
        i:=e[cur[i]].x;
      end;
      mf:=mf+flow;
      now:=s;
    end;
    p:=cur[now];
    f:=true;
    while p<>0 do
    begin
      pp:=e[p].x;
      if (e[p].y>0) and (dis[now]=dis[pp]+1) then
      begin
        cur[now]:=p;
        pre[pp]:=now;
        now:=pp;
        f:=false;
        break;
      end;
      p:=e[p].next;
    end;
    if f then
    begin
      dec(gap[dis[now]]);
      if gap[dis[now]]=0 then break;
      cur[now]:=a[now];
      p:=a[now];
      dis[now]:=t+1;
      while p<>0 do
      begin
        pp:=e[p].x;
        if (e[p].y>0) then dis[now]:=min(dis[pp]+1,dis[now]);
        p:=e[p].next;
      end;
      inc(gap[dis[now]]);
      if now<>s then now:=pre[now];
    end;
  end;
end;
begin
  read(n,m);
  s:=0;
  t:=n*2+1;
  for i:=1 to n do
  begin
    adde(s,i,1,0);
    adde(i+n,t,1,0);
  end;
  for i:=1 to m do
  begin
    read(u,v);
    ee[u,v]:=1;
  end;
  for i:=1 to n do
  for j:=1 to n do
  if i<>j then
  for k:=1 to n do
  if (i<>k) and (j<>k) then
  if (ee[i,k]=0) and (ee[i,j]=1) and (ee[j,k]=1) then ee[i,k]:=1;
  for i:=1 to n do
  for j:=1 to n do
  if (i<>j) and (ee[i,j]=1) then
  adde(i,j+n,1,0);
  sap;
  writeln(n-mf);
end.

评论

0条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据