题意是说,一个牧师要帮人举办婚礼庆典,给出每对新人的可用时间段s,e和举办庆典时长len,这个庆典只能在时间段前或时间段后举行并且这些时间段不能有冲突,问牧师能否为他们举办庆典,能就输出具体时间段。
解法:2-SAT
i表示甲婚礼前段,^i表示甲婚礼后段
j表示乙婚礼前段,^j表示乙婚礼后段
建图:
i与j有冲突,i-->^j,j-->^i
i与^j有冲突,i-->j,^j-->^i
^i与j有冲突,^i-->^j,j-->i
^i与^j有冲突,^i-->j,^j-->i
然后就按照赵爽同学写的那样强连通缩点,拓扑染色(具体看赵爽论文)。
#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <string.h>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <limits.h>
using namespace std;
int lowbit(int t){return t&(-t);}
int countbit(int t){return (t==0)?0:(1+countbit(t&(t-1)));}
int gcd(int a,int b){return (b==0)?a:gcd(b,a%b);}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a>b?b:a;}
#define LL long long
#define PI acos(-1.0)
#define N 1200*2
#define INF INT_MAX
#define eps 1e-8
#define FRE freopen("a.txt","r",stdin)
int low[N],dfn[N];
int belong[N];
bool inStack[N],vis[N];
vector<int> v[N],g[N];
stack<int> st;
int n,m;
int step,t;
int conflict[N];//缩点后有矛盾的点
int du[N];//入度
int color[N];//1为红色,-1为蓝色,红色输出
int top[N],cnt;
struct node
{
int s,e;
int len;
}c[1200];
void tarjan(int u)
{
int i;
step++;
st.push(u);
low[u]=dfn[u]=step;
vis[u]=1;
inStack[u]=1;
for(i=0;i<v[u].size();i++)
{
int x=v[u][i];
if(!vis[x])
{
tarjan(x);
low[u]=min(low[u],low[x]);
}
else
if(inStack[x])
low[u]=min(low[u],dfn[x]);
}
if(low[u]==dfn[u])
{
t++;
while(1)
{
int x=st.top();
st.pop();
belong[x]=t;
inStack[x]=0;
if(x==u)break;
}
}
}
void init()
{
int i;
for(i=0;i<=2*n;i++)v[i].clear();
}
bool isConflict(int a,int b,int c,int d)
{
if(a>=d || b<=c)return false;
return true;
}
void Build()
{
int i,j;
init();
for(i=1;i<=n-1;i++)
{
for(j=i+1;j<=n;j++)
{
if(isConflict(c[i].s, c[i].s+c[i].len, c[j].s, c[j].s+c[j].len))
{
v[i].push_back(j+n);
v[j].push_back(i+n);
}
if(isConflict(c[i].s, c[i].s+c[i].len, c[j].e-c[j].len, c[j].e))
{
v[i].push_back(j);
v[j+n].push_back(i+n);
}
if(isConflict(c[i].e-c[i].len, c[i].e, c[j].e-c[j].len, c[j].e))
{
v[i+n].push_back(j);
v[j+n].push_back(i);
}
if(isConflict(c[i].e-c[i].len, c[i].e, c[j].s, c[j].s+c[j].len))
{
v[i+n].push_back(j+n);
v[j].push_back(i);
}
}
}
}
void Rebuild()//逆图
{
int i,j;
memset(du,0,sizeof(du));
for(i=1;i<=2*n;i++)
{
for(j=0;j<v[i].size();j++)
{
int a=belong[i],b=belong[v[i][j]];
if(a!=b)
{
g[b].push_back(a);
du[a]++;
}
}
}
for(i=1;i<=n;i++)
{
int a=belong[i],b=belong[i+n];
conflict[a]=b;//缩点后有矛盾的点
conflict[b]=a;
}
}
void topsort()
{
int i,j;
queue<int> q;
for(i=1;i<=t;i++)
if(!du[i])q.push(i);
cnt=0;
while(!q.empty())
{
int x=q.front();
top[++cnt]=x;
q.pop();
for(i=0;i<g[x].size();i++)
{
int tmp=g[x][i];
du[tmp]--;
if(du[tmp]==0)
q.push(tmp);
}
}
}
void dfs_Blue(int u)
{
int i;
color[u]=-1;
for(i=0;i<g[u].size();i++)
{
int x=g[u][i];
if(!color[x])
dfs_Blue(x);
}
}
void dfs_Red()
{
int i,j;
memset(color,0,sizeof(color));
for(i=1;i<=cnt;i++)
{
int x=top[i];
if(!color[x])
{
color[x]=1;//Red
dfs_Blue(conflict[x]);//把所有与x有矛盾的点及其子孙染蓝色
}
}
}
void output()
{
int i,j;
printf("YES\n");
int t1,t2;
for(i=1;i<=n;i++)
{
int x=belong[i],y=belong[i+n];
if(color[x]==1)
{
t1=c[i].s;
t2=c[i].s+c[i].len;
}
if(color[y]==1)
{
t1=c[i].e-c[i].len;
t2=c[i].e;
}
printf("%02d:%02d %02d:%02d\n",t1/60,t1%60,t2/60,t2%60);
}
}
void solve()
{
int i,j;
memset(vis,0,sizeof(vis));
memset(inStack,0,sizeof(inStack));
t=0,step=0;
for(i=1;i<=2*n;i++)
if(!vis[i])tarjan(i);
for(i=1;i<=n;i++)
if(belong[i]==belong[i+n])
{
printf("NO\n");
return ;
}
Rebuild();
topsort();
dfs_Red();
output();
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
int i,j;
for(i=1;i<=n;i++)
{
int h1,m1,h2,m2;
scanf("%d:%d %d:%d %d",&h1,&m1,&h2,&m2,&c[i].len);
c[i].s=h1*60+m1;
c[i].e=h2*60+m2;
}
Build();
solve();
}
}