【题意】
有n个婚礼,每个婚礼有起始时间si,结束时间ti,还有一个主持时间ti,ti必须安排在婚礼的开始或者结束,主持由祭祀来做,但是只有一个祭祀,所以各个婚礼的主持时间不能重复,问你有没有可能正常的安排主持时间,不能输出no,能的话要输出具体的答案:即每个婚礼的主持时间段是什么样的。
【题解】
2-SAT判定问题,建图很简单,此略。
重点讲一下输出方案。
我们可以把处在同一个强连通分量中的点和边缩成一个点,得到新的有向图G1。然后,我们把G中的所有弧反向,得到图G2。
现在我们观察。由于已经进行了缩点的操作,因此G2中一定不存在圈,也就是说,具有拓扑结构。
我们把G中所有顶点置为“未着色”。按照拓扑顺序重复下面的操作:
1、选择第一个未着色的顶点x。把x染成红色。
2、把所有与x矛盾的顶点(如果存在bi,~bi∈B ,且bi属于x代表的强连通分量,~bi属于代表y的强连通分量,那么x和y就是互相矛盾的顶点)及其子孙全部全部染成蓝色。
3、重复操作1和2,直到不存在未着色的点为止。此时,G2中被染成红色的点在图G中对应的顶点集合,就对应着该2-SAT的一组解。
此实现可以递归。
详见代码中的draw(),del(),paint()。
【代码】
#include <iostream>
#include <vector>
using namespace std;
const int maxn=2005,maxe=maxn*maxn;
struct edge
{
int x,y,next;
}e[maxe];
int dfn[maxn],low[maxn],v[maxn],s[maxn],b[maxn],h[maxn],g[maxn],col[maxn];
int ss[maxn],tt[maxn],d[maxn],q[maxn];
int n,tot,cnt,times,t,tot2,st,ed;
vector<int> ant[maxn];
void ins(int x,int y)
{
e[++tot].x=x;e[tot].y=y;
e[tot].next=h[x];h[x]=tot;
}
void tarjan(int x)
{
int y,i;
times++;t++;
dfn[x]=low[x]=times;
v[x]=1;s[t]=x;
for (i=h[x];i;i=e[i].next)
{
y=e[i].y;
if (v[y]==0)
{
tarjan(y);
low[x]=min(low[x],low[y]);
}
if (v[y]==1)
low[x]=min(low[x],dfn[y]);
}
if (dfn[x]==low[x])
{
cnt++;
do
{
y=s[t--];
b[y]=cnt;v[y]=2;
}while (y!=x);
}
}
bool inter(int a,int b,int c,int d)
{
if (b<=c || d<=a) return false;
return true;
}
void build()
{
int i,j;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
if (i!=j)
{
if (inter(ss[i],ss[i]+d[i],ss[j],ss[j]+d[j]))
ins(i,j+n);
if (inter(ss[i],ss[i]+d[i],tt[j]-d[j],tt[j]))
ins(i,j);
if (inter(tt[i]-d[i],tt[i],ss[j],ss[j]+d[j]))
ins(i+n,j+n);
if (inter(tt[i]-d[i],tt[i],tt[j]-d[j],tt[j]))
ins(i+n,j);
}
}
void init()
{
scanf("%d\n",&n);
for (int i=1;i<=n;i++)
{
int x1,y1,x2,y2;
char ch;
scanf("%d:%d %d:%d %d\n",&x1,&y1,&x2,&y2,&d[i]);
ss[i]=x1*60+y1;tt[i]=x2*60+y2;
}
}
void work()
{
for (int i=1;i<=n+n;i++)
if (v[i]==0)
tarjan(i);
}
void rebuild()
{
int i;
for (i=1;i<=n;i++)
{
ant[b[i]].push_back(b[i+n]);
ant[b[i+n]].push_back(b[i]);
}
memset(h,0,sizeof(h));
tot2=tot;
tot=0;
for (i=1;i<=tot2;i++)
if (b[e[i].x]!=b[e[i].y])
{
g[b[e[i].x]]++;
ins(b[e[i].y],b[e[i].x]);
}
}
void toposort()
{
st=1;ed=0;
int i;
for (i=1;i<=cnt;i++)
if (g[i]==0) q[++ed]=i;
while (st<=ed)
{
int x=q[st++],y;
for (i=h[x];i;i=e[i].next)
{
y=e[i].y;
g[y]--;
if (g[y]==0) q[++ed]=y;
}
}
}
void paint(int x)
{
int i,y;
for (i=h[x];i;i=e[i].next)
{
y=e[i].y;
if (col[y]==0)
{
col[y]=col[x];
paint(y);
}
}
}
void del(int x)
{
int i,y;
for (i=0;i<ant[x].size();i++)
{
y=ant[x][i];
if (col[y]==0)
{
col[y]=2;
paint(y);
}
}
}
void draw()
{
for (int i=1;i<=ed;i++)
if (col[q[i]]==0)
{
col[q[i]]=1;
del(q[i]);
}
}
void print()
{
cout << "YES\n";
for (int i=1;i<=n;i++)
{
int x1,x2,y1,y2;
if (col[b[i]]==1)
{
x1=ss[i]/60;x2=ss[i]%60;y1=(ss[i]+d[i])/60;y2=(ss[i]+d[i])%60;
}
else
{
x1=(tt[i]-d[i])/60;x2=(tt[i]-d[i])%60;y1=tt[i]/60;y2=tt[i]%60;
}
if (x1<10) cout << "0" << x1 << ":";
else cout << x1 << ":";
if (x2<10) cout << "0" << x2 << " ";
else cout << x2 << " ";
if (y1<10) cout << "0" << y1 << ":";
else cout << y1 << ":";
if (y2<10) cout << "0" << y2 << "\n";
else cout << y2 << "\n";
}
}
int main()
{
freopen("pin.txt","r",stdin);
freopen("pou.txt","w",stdout);
int i;
init();
build();
work();
for (i=1;i<=n;i++)
if (b[i]==b[i+n])
{
cout << "NO\n";
return 0;
}
rebuild();
toposort();
draw();
print();
return 0;
}