题目链接:http://poj.org/problem?id=3683
题意:有n个婚礼要举行,但是只有一个牧师。第i个婚礼使用牧师的时间长为leni,可以在开始时或结束时使用。问能否使得n个婚礼均举行?
思路:对于婚礼i,i*2-1表示在开始使用牧师,i*2表示在结束使用牧师。枚举每一对不同的i和j:
(1)如果i*2-1和j*2-1冲突。连接i*2-1 j*2
(2)如果i*2-1和j*2冲突,连接i*2-1 j*2-1
(3)如果i*2和j*2-1冲突,连接i*2 j*2
(4)如果i*2和j*2冲突,连接i*2 j*2-1
#include <stdio.h>
#include <string.h>
#include <stack>
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
struct node
{
int v,next;
};
const int MAX=4005;
const int MAXE=5000005;
node edges[MAXE];
int head[MAX],e;
int dfn[MAX],low[MAX],visit[MAX],color[MAX],col[MAX];
int n,index,cnt;
stack<int> S;
int deg[MAX],ans[MAX],p[MAX];
int head1[MAX],e1;
node edges1[MAXE];
void Add(int u,int v)
{
edges[e].v=v;
edges[e].next=head[u];
head[u]=e++;
}
void Add1(int u,int v)
{
edges1[e1].v=v;
edges1[e1].next=head1[u];
head1[u]=e1++;
}
void Tarjan(int u)
{
int i,v;
low[u]=dfn[u]=++index;S.push(u);visit[u]=1;
for(i=head[u];i!=-1;i=edges[i].next)
{
v=edges[i].v;
if(!dfn[v])
{
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(visit[v]) low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
cnt++;
do
{
v=S.top();
S.pop();
visit[v]=0;
color[v]=cnt;
}while(u!=v);
}
}
void init()
{
memset(deg,0,sizeof(deg));
memset(head1,-1,sizeof(head1));
e1=0;
int i,u,v,x,y;
for(u=1;u<=2*n;u++)
{
for(i=head[u];i!=-1;i=edges[i].next)
{
v=edges[i].v;
if(color[v]!=color[u])
{
x=color[v];
y=color[u];
Add1(x,y);
deg[y]++;
}
}
}
while(!S.empty()) S.pop();
for(i=1;i<=cnt;i++) if(!deg[i]) S.push(i);
memset(p,0,sizeof(p));
while(!S.empty())
{
u=S.top();
S.pop();
if(!p[u]) p[u]=1,p[col[u]]=-1;
for(i=head1[u];i!=-1;i=edges1[i].next)
{
v=edges1[i].v;
if(--deg[v]==0) S.push(v);
}
}
memset(ans,0,sizeof(ans));
for(i=1;i<=n;i++)
{
if(p[color[i*2-1]]==1) ans[i]=1;
}
}
int TWO_ST()
{
int i;
memset(dfn,0,sizeof(dfn));
memset(visit,0,sizeof(visit));
index=cnt=0;
while(!S.empty()) S.pop();
for(i=1;i<=2*n;i++) if(!dfn[i]) Tarjan(i);
for(i=1;i<=n;i++)
{
if(color[i*2-1]==color[i*2]) return 0;
col[color[i*2-1]]=color[i*2];
col[color[i*2]]=color[i*2-1];
}
init();
return 1;
}
struct Node
{
int s,e,len;
};
Node a[MAX];
void deal()
{
if(!TWO_ST())
{
puts("NO");
return;
}
puts("YES");
int i,x,y;
for(i=1;i<=n;i++)
{
ans[i]?(x=a[i].s,y=a[i].s+a[i].len):(x=a[i].e-a[i].len,y=a[i].e);
printf("%02d:%02d %02d:%02d\n",x/60,x%60,y/60,y%60);
}
}
int OK(int s1,int len1,int s2,int len2)
{
return s1<s2+len2&&s2<s1+len1;
}
int main()
{
while(scanf("%d",&n)!=-1)
{
int i,j,h1,m1,h2,m2;
for(i=1;i<=n;i++)
{
scanf("%d:%d %d:%d %d",&h1,&m1,&h2,&m2,&a[i].len);
a[i].s=h1*60+m1;
a[i].e=h2*60+m2;
}
memset(head,-1,sizeof(head));
e=0;
int u,v;
for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(i!=j)
{
if(OK(a[i].s,a[i].len,a[j].s,a[j].len)) Add(i*2-1,j*2);
if(OK(a[i].s,a[i].len,a[j].e-a[j].len,a[j].len)) Add(i*2-1,j*2-1);
if(OK(a[i].e-a[i].len,a[i].len,a[j].s,a[j].len)) Add(i*2,j*2);
if(OK(a[i].e-a[i].len,a[i].len,a[j].e-a[j].len,a[j].len)) Add(i*2,j*2-1);
}
deal();
}
return 0;
}