题意: John是一个牧师,他们家乡人喜欢挤在一天结婚,而且都要John来主持。每段婚礼都必须有一个仪式,要么在婚礼开始的时候开始,要么正好在婚礼结束的时候结束。告诉你每段婚礼的开始时间和结束时间以及仪式持续时间。问:John能不能正好主持完所以仪式,没有时间冲突,输出每个婚礼无冲突的仪式始末时间。
思路: 2-sat模版题。设婚礼开始时启动仪式为A,反之为A'。如果A与B有冲突,那么连接A——B',以此类推这样建图。然后求强连通分量,判断是否有解,有解的话缩图,然后Topsort一下输出。
代码:
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<queue>
using namespace std;
#define N 1010
int n;
struct couple{
int s,t,d;
void init(char begin[],char end[],int dur)
{
int h,m;
d=dur;
sscanf(begin,"%d:%d",&h,&m);
s=h*60+m;
sscanf(end,"%d:%d",&h,&m);
t=h*60+m;
}
}c[N];
struct edge{
int id,next;
};
class graph{
private:
int eid,p[N<<1];
edge e[(N*N)<<3];
public:
void clear()
{
eid=0;
memset(p,-1,sizeof(p));
}
void insert(int from,int to)
{
e[eid].id=to;
e[eid].next=p[from];
p[from]=eid++;
}
int next(int i){return e[i].next;}
int head(int u){return p[u];}
int getid(int i){return e[i].id;}
}G,newG;
class twoSat{
private:
int top,index,newid,stack[N<<1],
instack[N<<1],in[N<<1],other[N<<1],
belong[N<<1],dfn[N<<1],low[N<<1],
color[N<<1];
public:
void clear()
{
top=index=newid=0;
memset(stack,0,sizeof(stack));
memset(instack,0,sizeof(instack));
memset(belong,0,sizeof(belong));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(other,0,sizeof(other));
memset(in,0,sizeof(in));
memset(color,0,sizeof(color));
}
bool isvisit(int v){return dfn[v];}
bool legal(int x1,int x2,int y1,int y2)
{
return x2<=y1 || y2<=x1;
}
void makeMap()
{
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) continue;
if(!legal(c[i].s , c[i].s+c[i].d , c[j].s , c[j].s+c[j].d))
G.insert(i,j+n);
if(!legal(c[i].s , c[i].s+c[i].d , c[j].t-c[j].d , c[j].t))
G.insert(i,j);
if(!legal(c[i].t-c[i].d , c[i].t , c[j].s , c[j].s+c[j].d))
G.insert(i+n,j+n);
if(!legal(c[i].t-c[i].d , c[i].t , c[j].t-c[j].d , c[j].t))
G.insert(i+n,j);
}
}
}
void Tarjan(int u)
{
int v,t;
dfn[u]=low[u]=++index;
stack[++top]=u;
instack[u]=1;
for(int i=G.head(u);i!=-1;i=G.next(i)){
v=G.getid(i);
if(!dfn[v]){
Tarjan(v);
low[u]=min(low[u],low[v]);
}else if(instack[v]){
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]){
newid++;
do{
t=stack[top--];
instack[t]=0;
belong[t]=newid;
}while(t!=u);
}
}
void contract()
{
int i,u,v;
newG.clear();
for(u=1;u<=2*n;u++){
for(i=G.head(u);i!=-1;i=G.next(i)){
v=G.getid(i);
if(belong[u]!=belong[v]){
newG.insert(belong[v],belong[u]);
in[belong[u]]++;
}
}
}
}
bool exist()
{
for(int i=1;i<=n;i++){
if(belong[i]==belong[i+n]) return false ; //判断是否有解
other[belong[i]]=belong[i+n];
other[belong[i+n]]=belong[i];
}
return true;
}
void Topsort()
{
int i,u,v;
queue<int> q;
for(i=1;i<=newid;i++)
if(!in[i]) q.push(i);
while(!q.empty()){
u=q.front(),q.pop();
if(!color[u]){
color[u]=1;
color[other[u]]=-1;
}
for(i=newG.head(u);i!=-1;i=newG.next(i)){
v=newG.getid(i);
if( !(--in[v]) ) q.push(v);
}
}
}
void putAnswer()
{
int h,m;
Topsort();
for(int i=1;i<=n;i++){
if(color[belong[i]]==1){
h=c[i].s/60;
m=c[i].s%60;
printf("%02d:%02d ",h,m);
h=(c[i].s+c[i].d)/60;
m=(c[i].s+c[i].d)%60;
printf("%02d:%02d\n",h,m);
}else{
h=(c[i].t-c[i].d)/60;
m=(c[i].t-c[i].d)%60;
printf("%02d:%02d ",h,m);
h=c[i].t/60;
m=c[i].t%60;
printf("%02d:%02d\n",h,m);
}
}
}
}TS;
void init()
{
G.clear();
TS.clear();
}
void solve()
{
int i;
TS.makeMap(); //建图
for(i=1;i<=2*n;i++) //求强连通分量
if(!TS.isvisit(i))
TS.Tarjan(i);
if(TS.exist()){ //判断是否有解
TS.contract(); //缩图
puts("YES");
TS.putAnswer(); //输出答案
}else puts("NO");
}
int main()
{
int duration;
char begin[20],end[20];
while(~scanf("%d",&n)){
init();
for(int i=1;i<=n;i++){
scanf("%s %s %d",begin,end,&duration);
c[i].init(begin,end,duration);
}
solve();
}
return 0;
}