题目分析:2-sat并求可行解。
一场婚礼可以在两个时间段中挑一个接受牧师的祝福,所以可以将这两个时间段作为一组。
如果一场婚礼的某个时间段与另一场婚礼的某个时间段冲突,则建边。
最后如果有可行解,则缩点后建反向图,跑一遍拓扑排序,每次从队列中取出的未染色的块染为红色,将对立块(~i所在的块)染为蓝色。最后所有染为红色的块中的元素即所求的可行解。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
#define REP( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i )
#define FOR( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define REV( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define CLR( a , x ) memset ( a , x , sizeof a )
#define CPY( a , x ) memcpy ( a , x , sizeof a )
const int MAXN = 2000 ;
const int MAXE = 2000000 ;
struct Edge {
int v ;
Edge* next ;
} E[MAXE] , *H[MAXN] , *cur , t_E[MAXE] , *t_H[MAXN] , *t_cur ;
struct Point {
int st , ed ;
} p[MAXN] ;
int dfn[MAXN] , low[MAXN] , scc[MAXN] , scc_cnt ;
int S[MAXN] , top , dfs_clock ;
int n , m ;
int in[MAXN] ;
int Q[MAXN] , head , tail ;
int color[MAXN] ;
int opp[MAXN] ;
void init () {
cur = E ;
top = scc_cnt = dfs_clock = 0 ;
CLR ( H , 0 ) ;
CLR ( dfn , 0 ) ;
CLR ( scc , 0 ) ;
}
void t_init () {
t_cur = t_E ;
CLR ( t_H , 0 ) ;
CLR ( in , 0 ) ;
}
void addedge ( int u , int v ) {
cur -> v = v ;
cur -> next = H[u] ;
H[u] = cur ++ ;
}
void t_addedge ( int u , int v ) {
t_cur -> v = v ;
t_cur -> next = t_H[u] ;
t_H[u] = t_cur ++ ;
}
void tarjan ( int u ) {
dfn[u] = low[u] = ++ dfs_clock ;
S[top ++] = u ;
for ( Edge* e = H[u] ; e ; e = e -> next ) {
int v = e -> v ;
if ( !dfn[v] ) {
tarjan ( v ) ;
low[u] = min ( low[u] , low[v] ) ;
} else if ( !scc[v] ) low[u] = min ( low[u] , dfn[v] ) ;
}
if ( low[u] == dfn[u] ) {
++ scc_cnt ;
do {
scc[S[-- top]] = scc_cnt ;
} while ( u != S[top] ) ;
}
}
int ok () {
REP ( i , 0 , n << 1 ) if ( !dfn[i] ) tarjan ( i ) ;
REP ( i , 0 , n ) if ( scc[i << 1] == scc[i << 1 | 1] ) return 0 ;
REP ( i , 0 , n ) {
opp[scc[i << 1]] = scc[i << 1 | 1] ;
opp[scc[i << 1 | 1]] = scc[i << 1] ;
}
return 1 ;
}
int check ( int i , int j ) {
return p[i].st < p[j].ed && p[j].st < p[i].ed ;
}
void topo () {
head = tail = 0 ;
CLR ( color , 0 ) ;
FOR ( i , 1 , scc_cnt ) if ( !in[i] ) Q[tail ++] = i ;
while ( head != tail ) {
int u = Q[head ++] ;
if ( !color[u] ) {
color[u] = 1 ;
color[opp[u]] = 2 ;
for ( Edge* e = t_H[u] ; e ; e = e -> next )
if ( -- in[e -> v] == 0 )
Q[tail ++] = e -> v ;
}
}
}
void solve () {
int h1 , h2 , m1 , m2 , d ;
init () ;
REP ( i , 0 , n ) {
scanf ( "%d:%d %d:%d %d" , &h1 , &m1 , &h2 , &m2 , &d ) ;
p[i << 1].st = h1 * 60 + m1 ;
p[i << 1].ed = h1 * 60 + m1 + d ;
p[i << 1 | 1].st = h2 * 60 + m2 - d ;
p[i << 1 | 1].ed = h2 * 60 + m2 ;
}
REP ( i , 0 , n ) REP ( j , i + 1 , n ) {
int Li = i << 1 ;
int Lj = j << 1 ;
int Ri = i << 1 | 1 ;
int Rj = j << 1 | 1 ;
if ( check ( Li , Lj ) ) addedge ( Li , Rj ) , addedge ( Lj , Ri ) ;
if ( check ( Li , Rj ) ) addedge ( Li , Lj ) , addedge ( Rj , Ri ) ;
if ( check ( Ri , Lj ) ) addedge ( Ri , Rj ) , addedge ( Lj , Li ) ;
if ( check ( Ri , Rj ) ) addedge ( Ri , Lj ) , addedge ( Rj , Li ) ;
}
if ( ok () ) {
printf ( "YES\n" ) ;
t_init () ;
REP ( i , 0 , n << 1 )
for ( Edge* e = t_H[i] ; e ; e = e -> next )
if ( scc[i] != scc[e -> v] ) {
t_addedge ( scc[e -> v] , scc[i] ) ;
++ in[scc[i]] ;
}
topo () ;
REP ( i , 0 , n << 1 )
if ( color[scc[i]] == 1 )
printf ( "%02d:%02d %02d:%02d\n" , p[i].st / 60 , p[i].st % 60 , p[i].ed / 60 , p[i].ed % 60 ) ;
} else printf ( "NO\n" ) ;
}
int main () {
while ( ~scanf ( "%d" , &n ) ) solve () ;
return 0 ;
}