poj 3683 Priest John's Busiest Day 2_sat

题目大意

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

 

分析

  把一个婚礼分成两个点,分别代表一场婚礼开头主持和结束主持(用分钟算)的时间。那么就把问题转换成了一个2-SAT问题。若两个点之间有冲突(也就是时间有重合)则连边(具体见程序)。然后就是裸的2-SAT输出问题了(我打了200+的tarjan+拓扑)(要把tarjan的数组设大一些)。

 

代码

type
  arr=record
    x,y,next:longint;
end;

var
  a,a1:array[1..2000000] of arr;
  f:array[0..2000] of boolean;
  ls,zan,g,con,b,c,co:array[0..2000] of longint;
  dfn,low:array[0..3000] of longint;
  x,y,z:array[0..5000] of longint;
  tot,sum,n,m:longint;
  i,j,k:longint;
  e,d:longint;
  cc:char;
  s:string;

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

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

procedure dfs(x:longint);
var
  i:longint;
begin
  inc(d);
  dfn[x]:=d;
  low[x]:=d;
  inc(tot);
  zan[tot]:=x;
  f[x]:=true;
  i:=ls[x];
  while i>0 do
    with a[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 low[x]=dfn[x] then
  begin
    inc(sum);
    repeat
      i:=zan[tot];
      dec(tot);
      f[i]:=false;
      g[i]:=sum;
    until i=x;
  end;
end;

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

procedure topsort;
var
  i,j,k:longint;
  head,tail:longint;
begin
  head:=0;
  tail:=0;
  fillchar(b,sizeof(b),0);
  for i:=1 to sum do
    if c[i]=0 then
      begin
        tail:=tail+1;
        b[tail]:=i;
      end;
  if tail=0 then exit;
  repeat
    head:=head+1;
    i:=ls[b[head]];
    while i<>0 do
      with a[i] do
        begin
          c[y]:=c[y]-1;
          if c[y]=0
            then
              begin
                tail:=tail+1;
                b[tail]:=y;
              end;
          i:=next;
        end;
  until tail=head;
end;

procedure set_b(r:longint);
var
  i,j,k:longint;
begin
  i:=ls[r];
  co[r]:=-1;
  while i>0 do
    with a[i] do
      begin
        if co[y]=0
          then set_b(y);
        i:=next;
      end;
end;

procedure set_r;
var
  i,j,k:longint;
begin
  for i:=1 to sum do
    if co[b[i]]=0
      then
        begin
          co[b[i]]:=1;
          set_b(con[b[i]]);
        end;
end;

procedure print;
var
  i,t1,t2:longint;
begin
  writeln('YES');
  for i:=1 to n do
  begin
    if co[g[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,j,k:longint;
begin
  for i:=1 to n do
    begin
      if g[i]=g[i+n] then
        begin
          writeln('NO');
          exit;
        end;
      con[g[i]]:=g[i+n];
      con[g[i+n]]:=g[i];
    end;
  fillchar(ls,sizeof(ls),0);
  fillchar(c,sizeof(c),0);
  a1:=a;
  fillchar(a,sizeof(a),0);
  j:=e;
  e:=0;
  for i:=1 to j do
    with a1[i] do
      if g[x]<>g[y] then
        begin
          add(g[y],g[x]);
          c[g[x]]:=c[g[x]]+1;
        end;
  topsort;
  set_r;
  print;
end;

function check(x,y,x1,y1:longint):boolean;
begin
  if (y<=x1) or (y1<=x) then exit(false);
  check:=true;
end;

procedure init;
var
  i,j,k:longint;
begin
  readln(n);
  for i:=1 to n do
    begin
      s:='';
      read(cc); s:=cc;
      read(cc); s:=s+cc;
      val(s,j);
      read(cc);
      s:='';
      read(cc); s:=cc;
      read(cc); s:=s+cc;
      val(s,k);
      x[i]:=j*60+k;
      read(cc);
      s:='';
      read(cc); s:=cc;
      read(cc); s:=s+cc;
      val(s,j);
      read(cc);
      s:='';
      read(cc); s:=cc;
      read(cc); s:=s+cc;
      val(s,k);
      y[i]:=j*60+k;
      read(z[i]);
      readln;
    end;
end;

begin
  init;
  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(i+n,j+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;
  tarjan;
  work;
end.


posted @ 2016-06-13 19:34  一个响亮的蒟蒻  阅读(124)  评论(0编辑  收藏  举报