POJ--3683[Priest John's Busiest Day] 2-SAT第四题

45 篇文章 0 订阅
题目描述:

有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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__简言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值