题意:
安排婚礼。有 n 项婚礼,每项婚礼的举办时间为 s,结束时间为 e,持续时间为 d,婚礼举办开始的时间还有一个特殊的要求必须在(s~s+d)或者(e-d~e),然后输出安排的方式。
分析:
将 n 项婚礼安排为两组,第一组在 s 的时间开始举办,第二组在 e-d 的时间开始举办,然后这很显然和 2-sat 求解的类型相似,用 2-sat 求解。
在处理矛盾建边的过程中,我开始想用 2 * n 个点建立关系,然后 if,else 写个没完,还搞的稀里糊涂。之后,我发现用 4 * n 个节点建边更简单,2 * n 点表示婚礼开始时间,其他2 * n 个点为取反,其中,i 与 i + n 中,只能取一个,关系为 i xor i + n = 1;此外根据时间冲突,产生的矛盾关系,则 时间段 a && 时间段 b = 0。
最后求完强连通以后,要需要输出结果,需要反向建边,并拓扑排序。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 11000;
const int inf = 1000000000;
struct T{
int S, E;
}tim[maxn];
bool cmp( T a, T b )
{
if( a.S < b.E && a.S > b.S && a.E > b.E ||
a.S < b.S && a.E > b.S && a.E < b.E ||
a.S <= b.S && a.E >= b.E ||
a.S >= b.S && a.E <= b.E )
return true;
return false;
}
vector<int>edge[maxn];
int n, m;
int tmpdfn, dfn[maxn], low[maxn], inst[maxn], belong[maxn], st[maxn], top, scnt;
void tarjan( int u )
{
int i, v, t, size;
low[u] = dfn[u] = tmpdfn++;
st[top++] = u;
inst[u] = 1;
size = edge[u].size();
for( i = 0; i < size; i++ )
{
v = edge[u][i];
if( dfn[v] == -1 )
{
tarjan( v );
low[u] = min( low[u], low[v] );
}
else if( inst[v] )low[u] = min( low[u], dfn[v] );
}
if( dfn[u] == low[u] )
{
do{ belong[t = st[--top]] = scnt; inst[t] = 0; }while( t != u );
scnt++;
}
}
bool SCC()
{
int i;
top = 0;
tmpdfn = scnt = 1;
memset( dfn, -1, sizeof(dfn) );
memset( inst, 0, sizeof(inst) );
for( i = 1; i <= n * 2; i++ )if( dfn[i] == -1 )tarjan( i );
for( i = 1; i <= n; i++ )if( belong[i] == belong[i + n] )return false;
return true;
}
int opp[maxn], in[maxn], color[maxn];
vector<int>arc[maxn];
queue<int>q;
void rebuild()
{
memset( in, 0, sizeof(in) );
int u, v, i, size;
for( i = 1; i <= n; i++ )
{
opp[belong[i]] = belong[i + n];
opp[belong[i + n]] = belong[i];
}
for( i = 1; i <= n * 2; i++ )arc[i].clear();
for( u = 1; u <= n * 2; u++ )
{
size = edge[u].size();
for( i = 0; i < size; i++ )
{
v = edge[u][i];
if( belong[u] != belong[v] )
{
arc[belong[v]].push_back( belong[u] );
in[belong[u]]++;
}
}
}
}
void topusort()
{
int i, j, u, v, size;
while( !q.empty() )q.pop();
memset( color, 0, sizeof(color) );
for( i = 1; i < scnt; i++ )if( !in[i] )
q.push( i );
while( !q.empty() )
{
u = q.front(); q.pop();
if( !color[u] )color[u] = 1, color[opp[u]] = 2;
size = arc[u].size();
for( i = 0; i < size; i++ )
{
v = arc[u][i];
in[v]--;
if( !in[v] )q.push( v );
}
}
}
int main()
{
int i, j, u, v, s, e, dif;
while( ~scanf( "%d", &n ) )
{
for( i = 1; i <= n * 4; i++ )edge[i].clear();
for( i = 1; i <= n; i++ )
{
int x, y, xx, yy;
scanf( "%d:%d%d:%d%d", &x, &y, &xx, &yy, &dif );
s = x * 60 + y;
e = xx * 60 + yy;
tim[i].S = s, tim[i].E = s + dif;
tim[i + n].S = e - dif, tim[i + n].E = e;
}
for( i = 1; i <= n; i++ )
{
u = i; v = i + n;
edge[u].push_back( v + 2 * n );
edge[v].push_back( u + 2 * n );
edge[v + 2 * n].push_back( u );
edge[u + 2 * n].push_back( v );
}
n *= 2;
for( i = 1; i <= n; i++ )
for( j = i + 1; j <= n; j++ )if( cmp( tim[i], tim[j] ) )
{
edge[i].push_back( j + n );
edge[j].push_back( i + n );
}
if( SCC() )
{
puts( "YES" );
rebuild();
topusort();
n /= 2;
for( i = 1; i <= n; i++ )
if( color[belong[i]] == 1 )printf( "%02d:%02d %02d:%02d\n", tim[i].S / 60, tim[i].S % 60, tim[i].E / 60, tim[i].E % 60 );
else printf( "%02d:%02d %02d:%02d\n", tim[i + n].S / 60, tim[i + n].S % 60, tim[i + n].E / 60, tim[i + n].E % 60 );
}
else
puts( "NO" );
}
return 0;
}
/*
3
08:00 09:00 30
08:15 09:00 20
08:30 08:50 1
3
08:00 09:00 30
08:15 09:00 10
08:30 08:50 10
6
08:00 09:00 30
08:15 09:00 10
08:30 08:50 10
08:00 10:00 20
09:00 09:20 10
09:00 09:40 20
5
08:00 09:00 30
08:15 09:00 10
08:30 08:50 10
08:00 10:00 20
09:00 09:20 10
9
08:00 09:00 30
08:15 09:00 10
08:30 08:50 10
08:00 10:00 20
09:00 09:20 10
09:00 09:40 20
10:00 10:30 10
10:20 10:30 10
10:10 10:20 10
*/