371. 牧师约翰最忙碌的一天

题目链接

371. 牧师约翰最忙碌的一天

牧师约翰在 91 日这天非常的忙碌。

N 对情侣在这天准备结婚,每对情侣都预先计划好了婚礼举办的时间,其中第 i 对情侣的婚礼从时刻 Si 开始,到时刻 Ti 结束。

婚礼有一个必须的仪式:站在牧师面前聆听上帝的祝福。

这个仪式要么在婚礼开始时举行,要么在结束时举行。

i 对情侣需要 D_i 分钟完成这个仪式,即必须选择 SiSi+DiTiDiTi 两个时间段之一。

牧师想知道他能否满足每场婚礼的要求,即给每对情侣安排SiSi+DiTiDiTi,使得这些仪式的时间段不重叠。

若能满足,还需要帮牧师求出任意一种具体方案。

注意,约翰不能同时主持两场婚礼,且 所有婚礼的仪式均发生在 91 日当天

如果一场仪式的结束时间与另一场仪式的开始时间相同,则不算重叠。

例如:一场仪式安排在 08:0009:00,另一场仪式安排在 09:0010:00,则不认为两场仪式出现重叠。

输入格式

第一行包含整数 N

接下来 N 行,每行包含 Si,Ti,Di,其中 SiTihh:mm 形式。

输出格式

第一行输出能否满足,能则输出 YES,否则输出 NO

接下来 N 行,每行给出一个具体时间段安排。

数据范围

1N1000

输入样例:

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

输出样例:

YES 08:00 08:30 08:40 09:00

解题思路

2-SAT

由于 [s,s+d][td,t] 这两个区间只能选择一个,不妨看成一个命题,即令 ¬x 表示 [s,s+d]x 表示 [td,t],当两个区间重叠时,存在这样两个区间 [si,si+di],[sj,sj+dj] 或者 [si,si+di],[tjdj,tj] 或者 [tidi,ti],[sj,sj+dj] 或者 [tidi,ti],[tjdj,tj],以 [si,si+di],[sj,sj+dj] 这两个区间重叠为例,即不能存在一种逻辑 ¬xi 为真并且 ¬xj
为真,故当 ¬xi 为真时,必然有 ¬xj 为假,即有 xixj,则可将该问题转化为 2-SAT 问题

  • 时间复杂度:(n2)

代码

// Problem: 牧师约翰最忙碌的一天 // Contest: AcWing // URL: https://www.acwing.com/problem/content/373/ // Memory Limit: 128 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=2005,M=N*N; int n; int h[N],ne[M],e[M],idx; int dfn[N],low[N],timestamp,scc_cnt,stk[N],top,id[N]; bool in_stk[N]; struct A { int s,t,d; }a[N/2]; void add(int a,int b) { e[idx]=b,ne[idx]=h[a],h[a]=idx++; } bool over_lap(int a,int b,int c,int d) { return b>c&&d>a; } void tarjan(int x) { dfn[x]=low[x]=++timestamp; stk[++top]=x,in_stk[x]=true; for(int i=h[x];~i;i=ne[i]) { int y=e[i]; if(!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); } else if(in_stk[y]) low[x]=min(low[x],dfn[y]); } if(low[x]==dfn[x]) { int y; scc_cnt++; do { y=stk[top--]; in_stk[y]=false; id[y]=scc_cnt; }while(y!=x); } } int main() { memset(h,-1,sizeof h); scanf("%d",&n); for(int i=0;i<n;i++) { int hhs,mms,hht,mmt,d; scanf("%d:%d %d:%d %d",&hhs,&mms,&hht,&mmt,&d); a[i]={hhs*60+mms,hht*60+mmt,d}; } for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) { if(over_lap(a[i].s,a[i].s+a[i].d,a[j].s,a[j].s+a[j].d))add(i<<1|1,j<<1),add(j<<1|1,i<<1); if(over_lap(a[i].t-a[i].d,a[i].t,a[j].s,a[j].s+a[j].d))add(i<<1,j<<1),add(j<<1|1,i<<1|1); if(over_lap(a[i].s,a[i].s+a[i].d,a[j].t-a[j].d,a[j].t))add(i<<1|1,j<<1|1),add(j<<1,i<<1); if(over_lap(a[i].t-a[i].d,a[i].t,a[j].t-a[j].d,a[j].t))add(i<<1,j<<1|1),add(j<<1,i<<1|1); } for(int i=0;i<2*n;i++) if(!dfn[i])tarjan(i); for(int i=0;i<n;i++) if(id[i<<1]==id[i<<1|1]) { puts("NO"); return 0; } puts("YES"); for(int i=0;i<n;i++) if(id[i<<1|1]>id[i<<1]) printf("%02d:%02d %02d:%02d\n",(a[i].t-a[i].d)/60,(a[i].t-a[i].d)%60,a[i].t/60,a[i].t%60); else printf("%02d:%02d %02d:%02d\n",a[i].s/60,a[i].s%60,(a[i].s+a[i].d)/60,(a[i].s+a[i].d)%60); return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16949662.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(50)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示