// 题目来源:POJ 3683
// 题目大意:有n对新人要举行仪式,每对都有两个时间段可以选择,问是否可以所有新人的仪式时间不重叠
// 解决方法:2-sat的一眼题,把仪式可以选择的两个时间段看成两个点,仪式时间重叠的即为矛盾关系
// 特别注意:输出要按输入顺序!不要按照自己处理的顺序来。
#include <cstdio>
#define o 10000
#define _ 1000000
void link( int, int ); // 保存原图必须边
void link2( int, int ); // 保存缩点图(转成反边)
bool judge( int, int, int, int ); // 判断时间段是否重叠
void tarjan( int ); // 强连通分量缩点
void topsort( int ); // 拓扑排序
void dfs( int ); // 递归染色
void print( int, int ); // 转换格式输出
int next[_*2], g[_*2], next2[_], g2[_];
int h[o], h2[o], stack[o], dfn[o], low[o], a[o], b[o], c[o], code[o], id[o], done[o], cfl[o], color[o];
int n, t, t2, top, tt, index, cnt;
char st[10];
bool ins[o];
int main( )
{
freopen( "3683.in", "r", stdin );
freopen( "3683.out", "w", stdout );
scanf( "%d", &n );
for( int i = 1; i <= n; i++ )
{
scanf( "%s", st );
a[i] = ( st[0]-48 )*600 + ( st[1]-48 )*60;
a[i] += ( st[3]-48 )*10 + st[4]-48;
scanf( "%s", st );
b[i] = ( st[0]-48 )*600 + ( st[1]-48 )*60;
b[i] += ( st[3]-48 )*10 + st[4]-48;
scanf( "%d", &c[i] );
}
for( int i = 1; i <= n; i++ )
for( int j = i + 1; j <= n; j++ )
{
if( !judge( a[i], a[i]+c[i], a[j], a[j]+c[j] ) )
{
link( i, j+n );
link( j, i+n );
}
if( !judge( a[i], a[i]+c[i], b[j]-c[j], b[j] ) )
{
link( i, j );
link( j+n, i+n );
}
if( !judge( b[i]-c[i], b[i], a[j], a[j]+c[j] ) )
{
link( i+n, j+n );
link( j, i );
}
if( !judge( b[i]-c[i], b[i], b[j]-c[j], b[j] ) )
{
link( i+n, j );
link( j+n, i );
}
}
for( int i = 1; i <= 2*n; i++ )
if( !dfn[i] ) tarjan( i );
for( int i = 1; i <= n; i++ )
if( code[i] == code[i+n] )
{
printf( "NO" );
return 0;
}
printf( "YES\n" );
int j;
for( int i = 1; i <= 2*n; i++ )
for( int k = h[i]; k; k = next[k] )
{
j = g[k];
if( code[i] != code[j] )
{
link2( code[j], code[i] );
id[ code[i] ]++;
}
}
for( int i = 1; i <= cnt; i++ )
if( id[i] == 0 ) topsort( i );
for( int i = 1; i <= n; i++ )
{
cfl[ code[i] ] = code[i+n];
cfl[ code[i+n] ] = code[i];
}
for( int ii = 1; ii <= cnt; ii++ )
{
int i = done[ii];
if( color[i] != 0 ) continue;
color[i] = 1;
dfs( cfl[i] );
}
for( int i = 1; i <= n; i++ )
if( color[ code[i] ] == 1 )
print( a[i], a[i]+c[i] );
else
print( b[i]-c[i], b[i] );
}
void link( int aa, int bb )
{
next[++t] = h[aa];
h[aa] = t;
g[t] = bb;
}
void link2( int aa, int bb )
{
next2[++t2] = h2[aa];
h2[aa] = t2;
g2[t2] = bb;
}
bool judge( int aa, int bb, int cc, int dd )
{
if( bb <= cc || dd <= aa ) return 1;
return 0;
}
void tarjan( int i )
{
int j;
dfn[i] = low[i] = ++index;
stack[++top] = i;
ins[i] = true;
for( int k = h[i]; k; k = next[k] )
{
j = g[k];
if( !dfn[j] )
{
tarjan( j );
if( low[j] < low[i] ) low[i] = low[j];
}
else if( ins[j] && dfn[j] < low[i] )
low[i] = dfn[j];
}
if( dfn[i] == low[i] )
{
cnt++;
do
{
j = stack[top--];
code[j] = cnt;
ins[j] = false;
}
while( i != j );
}
}
void topsort( int i )
{
int j;
id[i] = -1;
done[++tt] = i;
for( int k = h2[i]; k; k = next2[k] )
{
j = g2[k];
id[j]--;
if( id[j] == 0 ) topsort( j );
}
}
void dfs( int i )
{
int j;
color[i] = 2;
for( int k = h2[i]; k; k = next2[k] )
{
j = g2[k];
if( color[j] == 0 ) dfs( j );
}
}
void print( int aa, int bb )
{
if( aa / 60 < 10 ) printf( "0" );
printf( "%d:", aa / 60 );
if( aa % 60 < 10 ) printf( "0" );
printf( "%d ", aa % 60 );
if( bb / 60 < 10 ) printf( "0" );
printf( "%d:", bb / 60 );
if( bb % 60 < 10 ) printf( "0" );
printf( "%d\n", bb % 60 );
}
【代码】POJ 3683
最新推荐文章于 2019-12-26 19:47:01 发布