POJ3683 Priest John's Busiest Day
Priest John's Busiest Day
n对新人举行婚礼,婚礼在不同时间段但可能重叠,婚礼有开始(Si)、结束(Ti)、仪式举行时间(Di),问能否给出一种举行方案,使得神父能参加所有的婚礼并举行仪式。
题解
每场婚礼两个选择,婚礼之间可能有冲突,明显的2-SAT问题。
\(O(n^2)\)连边,做完2-SAT输出即可。
对简化版选择方案的理解:出度少的编号小,所以选择更优。
co int N=2010,M=3000010;
int ver[M],next[M],head[N],dfn[N],low[N],c[N],s[N],ins[N];
int val[N],deg[N],opp[N],S[N],T[N],D[N];
int n,m,tot,num,t,p;
il void add(int x,int y){
ver[++tot]=y,next[tot]=head[x],head[x]=tot;
}
void tarjan(int x){
dfn[x]=low[x]=++num;
s[++p]=x,ins[x]=1;
for(int i=head[x];i;i=next[i]){
if(!dfn[ver[i]]) tarjan(ver[i]),low[x]=std::min(low[x],low[ver[i]]);
else if(ins[ver[i]]) low[x]=std::min(low[x],dfn[ver[i]]);
}
if(dfn[x]==low[x]){
++t;int y;
do y=s[p--],ins[y]=0,c[y]=t; while(x!=y);
}
}
il bool overlap(int a,int b,int c,int d){
return c<=a&&a<d||c<b&&b<=d||a<=c&&d<=b;
}
int main(){
read(n);
for(int i=1;i<=n;++i)
S[i]=read<int>()*60+read<int>(),T[i]=read<int>()*60+read<int>(),read(D[i]);
for(int i=1;i<n;++i)for(int j=i+1;j<=n;++j){
if(overlap(S[i],S[i]+D[i],S[j],S[j]+D[j])) add(i,n+j),add(j,n+i);
if(overlap(S[i],S[i]+D[i],T[j]-D[j],T[j])) add(i,j),add(n+j,n+i);
if(overlap(T[i]-D[i],T[i],S[j],S[j]+D[j])) add(n+i,n+j),add(j,i);
if(overlap(T[i]-D[i],T[i],T[j]-D[j],T[j])) add(n+i,j),add(n+j,i);
}
for(int i=1;i<=2*n;++i)if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;++i){
if(c[i]==c[n+i]) return puts("NO"),0;
opp[i]=n+i,opp[n+i]=i;
}
puts("YES");
for(int i=1;i<=2*n;++i) val[i]=c[i]>c[opp[i]];
for(int i=1;i<=n;++i){
if(val[i]==0) printf("%02d:%02d %02d:%02d\n",S[i]/60,S[i]%60,(S[i]+D[i])/60,(S[i]+D[i])%60);
else printf("%02d:%02d %02d:%02d\n",(T[i]-D[i])/60,(T[i]-D[i])%60,T[i]/60,T[i]%60);
}
return 0;
}
静渊以有谋,疏通而知事。
浙公网安备 33010602011771号