题目描述:
有n个婚礼,每个婚礼有起始时间si,结束时间ti,还有一个主持时间ti,ti必须安排在婚礼的开始或者结束,主持由祭祀来做,但是只有一个祭祀,所以各个婚礼的主持时间不能重复,问你有没有可能正常的安排主持时间,不能输出no,能的话要输出具体的答案:即每个婚礼的主持时间段是什么样的。
构图:
对于婚礼i和婚礼j。i表示在开始主持,i2表示在结束主持,j类似。
枚举每一对不同的i和j。
如果i和j冲突。连接i j2
如果i和j2冲突,连接i j
如果i2和j冲突,连接i2 j2
如果i2和j2冲突,连接i2 j
然后就是求强联通,topsort,输出答案。
CODE:
/*POJ2-SAT第四题*/
/*AC代码:141ms*/
#include <iostream>
#define MAXN 3005
using namespace std;
struct edge
{
int from,to,next;
};
struct edge E[4000005],E2[100005];
struct time
{
int s,e,len;
}T[MAXN];
int head[MAXN],ecnt,head2[MAXN],ecnt2;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN],Num[MAXN];
bool Instack[MAXN];
int opp[MAXN];//what a opposite;
int in[MAXN];
int Index,scc,top,N;
int ans[MAXN];//存染色后的结果
void Insert(int u,int v)
{
E[ecnt].from=u;
E[ecnt].to=v;
E[ecnt].next=head[u];
head[u]=ecnt++;
}
void Insert2(int u,int v)
{
E2[ecnt2].from=u;
E2[ecnt2].to=v;
E2[ecnt2].next=head2[u];
head2[u]=ecnt2++;
}
void Tarjan(int u)
{
int v,i;
Low[u]=DFN[u]=++Index;
Instack[u]=true;
Stack[++top]=u;
for(i=head[u];i!=-1;i=E[i].next)
{
v=E[i].to;
if(!DFN[v])
{
Tarjan(v);
if(Low[u]>Low[v])
Low[u]=Low[v];
}
else if(Instack[v]&&Low[u]>DFN[v])
Low[u]=DFN[v];
}
if(Low[u]==DFN[u])
{
scc++;
do{
v=Stack[top--];
Instack[v]=false;
Belong[v]=scc;
Num[scc]++;
}while(u!=v);
}
return;
}
bool Judge(int s1,int len1,int s2,int len2)
{
if(s1<s2+len2&&s2<s1+len1)
return true;
return false;
}
void Build_Map()
{
int i,j,h1,m1,h2,m2,len;
ecnt=0;
memset(head,-1,sizeof(head));
for(i=0;i<N;i++)
{
scanf("%d:%d%d:%d%d",&h1,&m1,&h2,&m2,&len);
T[i].s=h1*60+m1;
T[i].e=h2*60+m2;
T[i].len=len;
}
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
{
if(i==j) continue;
if(Judge(T[i].s,T[i].len,T[j].s,T[j].len)) Insert(i,j+N);
if(Judge(T[i].s,T[i].len,T[j].e-T[j].len,T[j].len)) Insert(i,j);
if(Judge(T[i].e-T[i].len,T[i].len,T[j].s,T[j].len)) Insert(i+N,j+N);
if(Judge(T[i].e-T[i].len,T[i].len,T[j].e-T[j].len,T[j].len)) Insert(i+N,j);
}
}
}
bool Sat()
{
int i;
memset(Instack,false,sizeof(Instack));
memset(DFN,0,sizeof(DFN));
memset(Low,0,sizeof(Low));
memset(Num,0,sizeof(Num));
Index=scc=top=0;
for(i=0;i<2*N;i++)
{if(!DFN[i]) Tarjan(i);}
for(i=0;i<N;i++)
{
if(Belong[i]==Belong[i+N])
return false;
opp[Belong[i]]=Belong[i+N];
opp[Belong[i+N]]=Belong[i];
}
return true;
}
void Solve()//反向构图+Topsort+染色
{
//printf("*\n");
int i,Q[20000],col[MAXN],u,v;
ecnt2=0;
memset(in,0,sizeof(in));
memset(head2,-1,sizeof(head2));
memset(col,0,sizeof(col));//color red blue
for(i=0;i<ecnt;i++)//反向建图
{
if(Belong[E[i].from]!=Belong[E[i].to])
{
Insert2(Belong[E[i].to],Belong[E[i].from]);//why reverse edge
in[Belong[E[i].from]]++;
}
}
//Topsort
int l=0,r=0;
for(i=0;i<scc;i++)//?
{if(in[i]==0) Q[r++]=i;}
while(l<r)
{
u=Q[l++];
if(col[u]==0)
{
col[u]=1;
col[opp[u]]=-1;
}
v=head2[u];
while(v!=-1)
{
if(--in[E2[v].to]==0)
Q[r++]=E2[v].to;
v=E2[v].next;
}
}
memset(ans,0,sizeof(ans));
for(i=0;i<N;i++)
if(col[Belong[i]]==1)
ans[i]=1;
}
void Output()//打印
{
int i,t1,t2;
for(i=0;i<N;i++)
{
if(ans[i])
{
t1=T[i].s;
t2=T[i].s+T[i].len;
}
else
{
t1=T[i].e-T[i].len;
t2=T[i].e;
}
printf("%02d:%02d %02d:%02d\n",t1/60,t1%60,t2/60,t2%60);
}
}
int main()
{
while(scanf("%d",&N)!=EOF)
{
Build_Map();
if(!Sat())
printf("NO\n");
else
{
printf("YES\n");
Solve();
Output();
}
}
return 0;
}