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;
}

posted on 2019-06-03 18:04  autoint  阅读(130)  评论(0)    收藏  举报

导航