# [POJ 3683] Priest John's Busiest Day【2-SAT】

• 2018-01-13
• 0
• 0

## Problem:

 Time Limit: 2000MS Memory Limit: 65536K Special Judge

Description

John is the only priest in his town. September 1st is the John's busiest day in a year because there is an old legend in the town that the couple who get married on that day will be forever blessed by the God of Love. This year Ncouples plan to get married on the blessed day. The i-th couple plan to hold their wedding from time Si to time Ti. According to the traditions in the town, there must be a special ceremony on which the couple stand before the priest and accept blessings. The i-th couple need Di minutes to finish this ceremony. Moreover, this ceremony must be either at the beginning or the ending of the wedding (i.e. it must be either from Si to Si + Di, or from Ti - Dito Ti). Could you tell John how to arrange his schedule so that he can present at every special ceremonies of the weddings.

Note that John can not be present at two weddings simultaneously.

Input

The first line contains a integer N ( 1 ≤ N ≤ 1000).
The next N lines contain the SiTi and DiSi and Ti are in the format of hh:mm.

Output

The first line of output contains "YES" or "NO" indicating whether John can be present at every special ceremony. If it is "YES", output another N lines describing the staring time and finishing time of all the ceremonies.

Sample Input

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

Sample Output

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

Source

POJ Founder Monthly Contest – 2008.08.31, Dagger and Facer

## Solution:

2-SAT 的模板题，需要用到较优的 2-SAT 求解算法。

【较优的 2-SAT 求解算法】

1. 根据限制条件建图
2. 使用 Tarjan 算法将原图进行强连通分量缩点
3. 若任意一对点在同一个强连通分量中，则该模型无解，否则一定有解。
4. 将强连通分量建反图
5. 在反图上进行拓扑排序，每取一个点就将其对称点删去（可以使用标记）。
6. 所有取到的点即为答案。

## Code: O(N+M) [12016K, 157MS]

```#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;

int N;
int S[1002], T[1002], D[1002];
int hh, mm;

inline int transfer(int hh, int mm) {return 60 * hh + mm;}

struct Edge{
int np;
Edge *nxt;
};

struct Graph{
Edge *V[2002], E[4000002];
int tope;

inline void addedge(int u, int v) {E[++tope].np = v, E[tope].nxt = V[u], V[u] = &E[tope];}
} G, C;

int dfn[2002], dfstime = 0;
int low[2002];
int Stack[2002], tops = 0;
int Status[2002];
int Color[2002], topc = 0, opp[2002];

inline void Tarjan(int u){
dfn[u] = low[u] = ++dfstime;
Stack[++tops] = u, Status[u] = 1;
for(register Edge *ne = G.V[u]; ne; ne = ne->nxt){
if(Status[ne->np] == 0){
Tarjan(ne->np);
low[u] = min(low[u], low[ne->np]);
}
else if(Status[ne->np] == 1) low[u] = min(low[u], dfn[ne->np]);
}
if(low[u] == dfn[u]){
while(Stack[tops + 1] != u){
Color[Stack[tops]] = topc;
Status[Stack[tops--]] = -1;
}
topc++;
}
}

int indeg[2002];
int deg0[2002], topd = 0;
int col[2002];

inline void del_opposite(int u){
if(col[u]) return;
col[u] = -1;
for(register Edge *ne = C.V[u]; ne; ne = ne->nxt)
del_opposite(ne->np);
}

inline void toposort(){
int u;
while(topd){
if(col[u = deg0[topd--]]) continue;
col[u] = 1, del_opposite(opp[u]);
for(register Edge *ne = C.V[u]; ne; ne = ne->nxt)
if(!col[ne->np] && !--indeg[ne->np]) deg0[++topd] = ne->np;
}
}

int main(){
scanf("%d", &N);
for(register int i = 0; i < N; i++){
scanf("%d:%d", &hh, &mm), S[i] = transfer(hh, mm);
scanf("%d:%d", &hh, &mm), T[i] = transfer(hh, mm);
scanf("%d", D + i);
}
for(register int i = 0; i < N; i++)
for(register int j = i + 1; j < N; j++){
if(S[i] < S[j] + D[j] && S[j] < S[i] + D[i]) G.addedge(i << 1, j << 1 ^ 1), G.addedge(j << 1, i << 1 ^ 1);
if(S[i] < T[j] && T[j] - D[j] < S[i] + D[i]) G.addedge(i << 1, j << 1), G.addedge(j << 1 ^ 1, i << 1 ^ 1);
if(T[i] - D[i] < S[j] + D[j] && S[j] < T[i]) G.addedge(i << 1 ^ 1, j << 1 ^ 1), G.addedge(j << 1, i << 1);
if(T[i] - D[i] < T[j] && T[j] - D[j] < T[i]) G.addedge(i << 1 ^ 1, j << 1), G.addedge(j << 1 ^ 1, i << 1);
}

N <<= 1, memset(Stack, -1, sizeof(Stack));
for(register int i = 0; i < N; i++)
if(!Status[i]) Tarjan(i);

for(register int i = 0; i < N; i += 2)
if(Color[i] == Color[i ^ 1]){
puts("NO");
return 0;
}
else opp[Color[i]] = Color[i ^ 1], opp[Color[i ^ 1]] = Color[i];

for(register int i = 0; i < N; i++)
for(register Edge *ne = G.V[i]; ne; ne = ne->nxt)
if(Color[i] != Color[ne->np]) C.addedge(Color[ne->np], Color[i]), indeg[Color[i]]++;
for(register int i = 0; i < topc; i++)
if(!indeg[i]) deg0[++topd] = i;
toposort();

puts("YES");
for(register int i = 0; i < N; i++)
if(col[Color[i]] == 1){
int st, en;
if(i & 1) st = T[i >> 1] - D[i >> 1], en = T[i >> 1];
else st = S[i >> 1], en = S[i >> 1] + D[i >> 1];
printf("%02d:%02d %02d:%02d\n", st / 60, st % 60, en / 60, en % 60);
}
return 0;
}
```

#### 评论

darkleafin.cf
(该域名已过期且被抢注。。)
darkleafin.github.io

49750

https://github.com/Darkleafin

OPEN AT 2017.12.10

Please refresh the page if the code cannot be displayed normally.

https://visualgo.net/en

- Theme by Qzhai