Priest John's Busiest Day(luogu)
Description
牧师约翰在9月1日这天非常的忙碌。
有 N 对情侣在这天准备结婚,每对情侣都预先计划好了婚礼举办的时间,其中第 i 对情侣的婚礼从时刻 Si 开始,到时刻 Ti 结束。
婚礼有一个必须的仪式:站在牧师面前聆听上帝的祝福。
这个仪式要么在婚礼开始时举行,要么在结束时举行。
第 i 对情侣需要 Di 分钟完成这个仪式,即必须选择 Si~Si+Di 或 Ti−Di~Ti 两个时间段之一。
牧师想知道他能否满足每场婚礼的要求,即给每对情侣安排Si~Si+Di 或 Ti−Di~Ti,使得这些仪式的时间段不重叠。
若能满足,还需要帮牧师求出任意一种具体方案。
注意,约翰不能同时主持两场婚礼。
如果一场仪式的结束时间与另一场仪式的开始时间相同,则不算重叠。
例如:一场仪式安排在08:00~09:00,另一场仪式安排在09:00~10:00,则不认为两场仪式出现重叠。
输入格式
第一行包含整数N。
接下来N行,每行包含 Si,Ti,Di ,其中 Si 和 Ti 是 h:m 形式。
输出格式
第一行输出能否满足,能则输出”YES”,否则输出”NO”。
接下来N行,每行给出一个具体时间段安排。
数据范围
1≤N≤1000
Solution
每对新人有两个选择和时间之间的约束关系使我们容易想到用2-SAT做。
先将小时换算成分钟(注意T1是秒)方便后续计算
将时间有冲突的新人之间连有向边。(详见代码)
此题关键在于输出安排
我们知道强联通缩点后按照编号从大到小即为拓扑序从小到大
而拓扑序大的点一定没有路径到拓扑序小的点
即当有合法方案时,对于每对新人,采取拓扑序大的点对应的选择
Code
#include <cstdio> #include <cstdlib> #include <vector> #include <algorithm> using namespace std; const int N=2e3+10,M=4e6+10; int n,s[N][2],t[N][2],s_h,s_m,t_h,t_m,a,b,c; int head[N],nxt[M],to[M],cnt,d[N],opp[N]; int dfn[N],low[N],tot,st[N],top,scc; bool in[N]; struct node { int st,ed; bool operator <(const node &o)const { return st<o.st; } }; vector <node> ans; void add(int x,int y) { to[++cnt]=y,nxt[cnt]=head[x],head[x]=cnt; } void tarjan(int u) { dfn[u]=low[u]=++tot; st[++top]=u,in[u]=true; for(int i=head[u];i;i=nxt[i]) { int v=to[i]; if(!dfn[v]) tarjan(v),low[u]=min(low[v],low[u]); else if(in[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { int z; scc++; do{ z=st[top--]; in[z]=false,d[z]=scc; }while(z!=u); } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d:%d %d:%d %d",&s_h,&s_m,&t_h,&t_m,&c); a=s_h*60+s_m,b=t_h*60+t_m; s[i][0]=a,t[i][0]=a+c,s[i][1]=b-c,t[i][1]=b; } for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) for(int p=0;p<2;p++) for(int q=0;q<2;q++) if(!(t[i][p]<=s[j][q] || t[j][q]<=s[i][p])) add(i+n*p,j+n*(1-q)),add(j+n*q,i+n*(1-p)); for(int i=1;i<=n*2;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=n;i++) { if(d[i]==d[i+n]) { puts("NO"); return 0; } opp[i]=i+n,opp[i+n]=i; } puts("YES"); for(int i=1;i<=n;i++) ans.push_back((node){s[i][d[i]>d[opp[i]]],t[i][d[i]>d[opp[i]]]}); sort(ans.begin(),ans.end()); for(int i=0;i<n;i++) { node tp=ans[i]; s_h=tp.st/60,s_m=tp.st%60; t_h=tp.ed/60,t_m=tp.ed%60; printf("%02d:%02d %02d:%02d\n",s_h,s_m,t_h,t_m); } return 0; }