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

题目链接

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

牧师约翰在 \(9\)\(1\) 日这天非常的忙碌。

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

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

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

\(i\) 对情侣需要 \(D\_i\) 分钟完成这个仪式,即必须选择 \(S_i \sim S_i+D_i\)\(T_i-D_i \sim T_i\) 两个时间段之一。

牧师想知道他能否满足每场婚礼的要求,即给每对情侣安排\(S_i \sim S_i+D_i\)\(T_i-D_i \sim T_i\),使得这些仪式的时间段不重叠。

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

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

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

例如:一场仪式安排在 \(08:00 \sim 09:00\),另一场仪式安排在 \(09:00 \sim 10:00\),则不认为两场仪式出现重叠。

输入格式

第一行包含整数 \(N\)

接下来 \(N\) 行,每行包含 \(S_i,T_i,D_i\),其中 \(S_i\)\(T_i\)\(hh:mm\) 形式。

输出格式

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

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

数据范围

\(1 \le N \le 1000\)

输入样例:

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]\)\([t-d,t]\) 这两个区间只能选择一个,不妨看成一个命题,即令 \(\neg x\) 表示 \([s,s+d]\)\(x\) 表示 \([t-d,t]\),当两个区间重叠时,存在这样两个区间 \([s_i,s_i+d_i],[s_j,s_j+d_j]\) 或者 \([s_i,s_i+d_i],[t_j-d_j,t_j]\) 或者 \([t_i-d_i,t_i],[s_j,s_j+d_j]\) 或者 \([t_i-d_i,t_i],[t_j-d_j,t_j]\),以 \([s_i,s_i+d_i],[s_j,s_j+d_j]\) 这两个区间重叠为例,即不能存在一种逻辑 \(\neg x_i\) 为真并且 \(\neg x_j\)
为真,故当 \(\neg x_i\) 为真时,必然有 \(\neg x_j\) 为假,即有 \(x_i\cup x_j\),则可将该问题转化为 2-SAT 问题

  • 时间复杂度:\((n^2)\)

代码

// 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;
}
posted @ 2022-12-04 12:29  zyy2001  阅读(35)  评论(0编辑  收藏  举报