poj 3683 Priest John's Busiest Day 2-SAT输出

题意:有n个婚礼,每个婚礼有起始时间si,结束时间ti,还有一个主持时间ti,ti必须安排在婚礼的开始或者结束,主持由祭祀来做,但是只有一个祭祀,所以各个婚礼的主持时间不能重复,问你有没有可能正常的安排主持时间,不能输出no,能的话要输出具体的答案:即每个婚礼的主持时间段是什么样的。


分析:把一个婚礼分成两个点,分别代表开始时间和结束时间。那么就把问题转换成了一个2-SAT问题。若两个点之间有冲突(也就是时间有重合)则连边。然后就是裸的2-SAT输出问题了。


把数组开大后就一次AC的感觉真是太好了。亏我之前那段旧代码调了那么久还是不知道那里出问题。看来把代码写的优美真的是很重要的啊(自夸ing)。


代码:

var
  n,e,d,tot,sum:longint;
  x,y,z,belong,last,stack,state,dfn,low,du,color,con:array[1..3000] of longint;
  f:array[1..3000] of boolean;
  side:array[1..2000000] of record
    x,y,next:longint;
  end;

function check(a,b,c,d:longint):boolean;
begin
  if (b<=c)or(d<=a) then exit(false);
  exit(true);
end;

procedure add(x,y:longint);
begin
  inc(e);
  side[e].x:=x;
  side[e].y:=y;
  side[e].next:=last[x];
  last[x]:=e;
end;

function min(x,y:longint):longint;
begin
  if x<y then exit(x)
         else exit(y);
end;

procedure init;
var
  i,j,t1,t2:longint;
  c:char;
  s:string;
begin
  readln(n);
  for i:=1 to n do
  begin
    read(c);s:=c;read(c);s:=s+c;val(s,t1);
    read(c);
    read(c);s:=c;read(c);s:=s+c;val(s,t2);
    x[i]:=t1*60+t2;
    read(c);
    read(c);s:=c;read(c);s:=s+c;val(s,t1);
    read(c);
    read(c);s:=c;read(c);s:=s+c;val(s,t2);
    y[i]:=t1*60+t2;
    readln(z[i]);
  end;
  for i:=1 to n-1 do
    for j:=i+1 to n do
    begin
      if check(x[i],x[i]+z[i],x[j],x[j]+z[j]) then
      begin
        add(i,j+n);
        add(j,i+n);
      end;
      if check(x[i],x[i]+z[i],y[j]-z[j],y[j]) then
      begin
        add(i,j);
        add(j+n,i+n);
      end;
      if check(y[i]-z[i],y[i],x[j],x[j]+z[j]) then
      begin
        add(i+n,j+n);
        add(j,i);
      end;
      if check(y[i]-z[i],y[i],y[j]-z[j],y[j]) then
      begin
        add(i+n,j);
        add(j+n,i);
      end;
    end;
end;

procedure dfs(x:longint);
var
  i:longint;
begin
  inc(d);
  dfn[x]:=d;
  low[x]:=d;
  inc(tot);
  stack[tot]:=x;
  f[x]:=true;
  i:=last[x];
  while i>0 do
    with side[i] do
    begin
      if dfn[y]=0
        then begin
               dfs(y);
               low[x]:=min(low[x],low[y]);
             end
        else if f[y] then low[x]:=min(low[x],dfn[y]);
      i:=next;
    end;
  if dfn[x]=low[x] then
  begin
    inc(sum);
    repeat
      i:=stack[tot];
      dec(tot);
      f[i]:=false;
      belong[i]:=sum;
    until i=x;
  end;
end;

procedure tarjan;
var
  i:longint;
begin
  fillchar(f,sizeof(f),false);
  for i:=1 to n*2 do
    if dfn[i]=0 then dfs(i);
end;

procedure topsort;
var
  head,tail,i:longint;
begin
  head:=0;
  tail:=0;
  for i:=1 to sum do
    if du[i]=0 then
    begin
      inc(tail);
      state[tail]:=i;
    end;
  repeat
    inc(head);
    i:=last[state[head]];
    while i>0 do
      with side[i] do
      begin
        dec(du[y]);
        if du[y]=0 then
        begin
          inc(tail);
          state[tail]:=y;
        end;
        i:=next;
      end;
  until head>=tail;
end;

procedure dfs_blue(x:longint);
var
  i:longint;
begin
  color[x]:=-1;
  i:=last[x];
  while i>0 do
    with side[i] do
    begin
      if color[y]=0 then dfs_blue(y);
      i:=next;
    end;
end;

procedure dfs_red;
var
  i:longint;
begin
  for i:=1 to sum do
    if color[state[i]]=0 then
    begin
      color[state[i]]:=1;
      dfs_blue(con[state[i]]);
    end;
end;

procedure print;
var
  i,t1,t2:longint;
begin
  writeln('YES');
  for i:=1 to n do
  begin
    if color[belong[i]]=1
      then begin
             t1:=x[i];
             t2:=x[i]+z[i];
           end
      else begin
             t1:=y[i]-z[i];
             t2:=y[i];
           end;
    if t1 div 60<10 then write(0);
    write(t1 div 60,':');
    if t1 mod 60<10 then write(0);
    write(t1 mod 60,' ');
    if t2 div 60<10 then write(0);
    write(t2 div 60,':');
    if t2 mod 60<10 then write(0);
    writeln(t2 mod 60);
  end;
end;

procedure work;
var
  i:longint;
begin
  for i:=1 to n do
  begin
    if belong[i]=belong[i+n] then
    begin
      writeln('NO');
      exit;
    end;
    con[belong[i]]:=belong[i+n];
    con[belong[i+n]]:=belong[i];
  end;
  fillchar(last,sizeof(last),0);
  for i:=1 to e do
    with side[i] do
      if belong[x]<>belong[y] then
      begin
        add(belong[y],belong[x]);
        inc(du[belong[x]]);
      end;
  topsort;
  dfs_red;
  print;
end;

begin
  init;
  tarjan;
  work;
end.


你可能感兴趣的:(poj 3683 Priest John's Busiest Day 2-SAT输出)