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.