Pku 3683 Priest John's Busiest Day

9 篇文章 0 订阅
7 篇文章 0 订阅

题目:

 Priest John's Busiest Day

来源:

 Pku 3683

题目大意:

 有N个区间(A,B),和一个值C。你可以选择使用(A,A+C)或(B-C,B)中一个区  间,使得所有选择出来的N个区间不相交,求方案。

数据范围:

 1 ≤ N ≤ 1000

样例:

 2
 08:00 09:00 30
 08:15 09:00 20
YES
08:00 08:30
08:40 09:00

做题思路:

 起初看到区间就茫然了,才发现原来就是其中的两段啊,坑。。

 时间表达换分钟,最后再换回来。

 设区间(A,B)分为I和I'两个区间。
 若I和J和J'相交,则I肯定不能选,从I向I'连一条边。
 若I仅和J相交,则I向J'连一条边,J向I'连一条边。
 若I仅和J'相交,则I向J连一条边,J'向I'连一条边。

 两个区间怎么确定呢?枚举呗

知识点:

 2-sat、kosaraju、枚举

type
 edge=record
 y,next:longint;
 end;
var
 a1,a2:array[0..1000010]of edge;
 first1,first2,q1,q2,f,a,b,c,col:array[0..2020]oflongint;
 time,tot1,tot2,n:longint;
//=========================================================
procedure build1(x,y:longint);
begin
 inc(tot1);
 a1[tot1].y:=y;
 a1[tot1].next:=first1[x];
 first1[x]:=tot1;
end;
//==================================================================
procedure build2(x,y:longint);
begin
 inc(tot2);
 a2[tot2].y:=y;
 a2[tot2].next:=first2[x];
 first2[x]:=tot2;
end;
//=================================================================
function pd(li,ri,lj,rj:longint):boolean;
begin
 if((lj<ri)and(rj>li))or((li<rj)and(ri>lj)) then exit(true);
 exit(false);
end;
//============================================================
procedure init;
var
 i,x1,x2,y1,y2,j,t:longint;
 ch1,ch2:char;
begin
 readln(n);
 tot1:=0;tot2:=0;
 fillchar(first1,sizeof(first1),0);
 fillchar(first2,sizeof(first2),0);
 fori:=1 to n do{<读入并转成分钟>}
  begin
  read(ch1,ch2);
  a[i]:=(ord(ch1)-ord('0'))*10+(ord(ch2)-ord('0'));
  read(ch1,ch1,ch2);
  a[i]:=a[i]*60+(ord(ch1)-ord('0'))*10+(ord(ch2)-ord('0'));
  read(ch1,ch1,ch2);
  b[i]:=(ord(ch1)-ord('0'))*10+(ord(ch2)-ord('0'));
  read(ch1,ch1,ch2);
  b[i]:=b[i]*60+(ord(ch1)-ord('0'))*10+(ord(ch2)-ord('0'));
  read(ch1);readln(c[i]);
  end;
 fori:=1 to n-1 do{<枚举每个区间与别的区间是否存在交集,存在则不连边>}
  forj:=i+1 to n do
  begin
   x1:=i*2-1;x2:=x1+1;
   y1:=j*2-1;y2:=y1+1;
   t:=0;
    ifpd(a[i],a[i]+c[i],a[j],a[j]+c[j]) then t:=1;
    ifpd(a[i],a[i]+c[i],b[j]-c[j],b[j]) then
     ift=0 then t:=2
           else t:=3;
   case t of
    1:begin
       build1(x1,y2);build1(y1,x2);
       build2(y2,x1);build2(x2,y1);
      end;
    2:begin
       build1(x1,y1);build1(y2,x2);
       build2(y1,x1);build2(x2,y2);
      end;
    3:begin
       build1(x1,x2);build2(x2,x1);
      end;
   end;
   t:=0;
    ifpd(b[i]-c[i],b[i],a[j],a[j]+c[j]) then t:=1;
    ifpd(b[i]-c[i],b[i],b[j]-c[j],b[j]) then
    ift=0 then t:=2
            else t:=3;
   case t of
    1:begin
        build1(x2,y2);build1(y1,x1);
        build2(y2,x2);build2(x1,y1);
       end;
    2:begin
        build1(x2,y1);build1(y2,x1);
        build2(y1,x2);build2(x1,y2);
       end;
    3:begin
        build1(x2,x1);build2(x1,x2);
       end;
   end;
   end;
end;
//===========================================================
procedure dfs1(x:longint);
var
 t:longint;
begin
 f[x]:=1;
 t:=first1[x];
 whilet>0 do
  begin
   iff[a1[t].y]=0 then dfs1(a1[t].y);
  t:=a1[t].next;
  end;
 inc(time);
 q1[time]:=x;
end;
//==========================================================
procedure dfs2(x:longint);
var
 t:longint;
begin
 f[x]:=time;
 t:=first2[x];
 whilet>0 do
  begin
   iff[a2[t].y]=0 then dfs2(a2[t].y);
  t:=a2[t].next;
  end;
end;
//==============================================================
procedure kosaraju;
var
 i:longint;
begin
 time:=0;
 fillchar(f,sizeof(f),0);
 fori:=1 to n*2 do
  iff[i]=0 then dfs1(i);
 time:=0;
 fillchar(f,sizeof(f),0);
 fori:=n*2 downto 1 do
  iff[q1[i]]=0 then
  begin
   inc(time);
   q2[time]:=q1[i];
   dfs2(q1[i]);
   end;
end;
//========================================================
procedure delete(x:longint);
var
 t:longint;
begin
 col[x]:=2;
 t:=first2[x];
 whilet>0 do
  begin
   if(col[a2[t].y]=0)and(f[x]=f[a2[t].y]) then delete(a2[t].y);
  t:=a2[t].next;
  end;
end;
//========================================================
procedure sat(x:longint);
var
 t:longint;
begin
 col[x]:=1;
 t:=first2[x];
 whilet>0 do
  begin
   if(col[a2[t].y]=0)and(f[x]=f[a2[t].y]) then sat(a2[t].y);
  t:=a2[t].next;
  end;
 ifodd(x) then delete(x+1) else delete(x-1);
end;
//=========================================================
procedure print(x,d:longint);{<把分钟转换成小时>}
var
 t:longint;
begin
 if d=1then
  begin
  t:=a[x] div 60;
   ift<=9 then write(0);
  write(t,':');
  t:=a[x] mod 60;
   ift<=9 then write(0);
  write(t,' ');
  inc(a[x],c[x]);
  t:=a[x] div 60;
   ift<=9 then write(0);
  write(t,':');
  t:=a[x] mod 60;
   ift<=9 then write(0);
  write(t);
  dec(a[x],c[x]);
  end
 else
  begin
  dec(b[x],c[x]);
  t:=b[x] div 60;
   ift<=9 then write(0);
  write(t,':');
  t:=b[x] mod 60;
   ift<=9 then write(0);
  write(t,' ');
  inc(b[x],c[x]);
  t:=b[x] div 60;
   ift<=9 then write(0);
  write(t,':');
  t:=b[x] mod 60;
   ift<=9 then write(0);
  write(t);
  end;
 writeln;
end;
//=========================================================
procedure main;
var
 i:longint;
begin
 fori:=1 to n do
  iff[2*i]=f[2*i-1] then
  begin
   writeln('NO');
   exit;
   end;
 fillchar(col,sizeof(col),0);
 fori:=time downto 1 do
  ifcol[q2[i]]=0 then sat(q2[i]);
 writeln('YES');
 fori:=1 to 2*n do
  ifcol[i]=1 then
   ifodd(i) then print((i+1) shr 1,1) else print((i+1) shr 1,0);
end;
//==========================================================
begin
 init;
 kosaraju;
 main;
end.
题目来源: http://poj.org/problem?id=3683

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值