poj 3683 Priest John's Busiest Day

每个婚礼只能选择从开始时间开始或者终点时间结束,所以可以2-sat。

建图:第i个婚礼  从开始时间开始用点 2*i 标记, 在终点时间结束用2*i+1 标记, 比较婚礼 i和j ,如果 2*i 和 2*j 有冲突, 则连一条 2*i到2*j+1的边(其他同理)......

输出解: 先将图缩点,然后建立一个逆向的图,在拓扑输出解。因为如果正向的图,选了一个点,它能到达的点都需要选,而如果逆向的话,我们只需要选择入度为0 的点(这个点可能是缩点前的圈),它只会对它的对立节点(或对立节点所在的圈)有影响,比如 选了2*k 所在的强连通分量,那么2*k+1所在的强连通分量就不能选。我们只需要标记一下颜色就可以了。然后将当前选择节点的出度所对应的点的入度减去,下一个入度为0的点,也是无约束的节点。

#include <cstdio>   
#include <iostream>
#include <queue>
#include <string.h>   
#include <cmath>
#include <vector>
#include <algorithm>   
using namespace std;
typedef long long ll;
#define sfint(x) scanf("%d",&x)
#define sfint2(x,y) scanf("%d%d",&x,&y)
#define sfint3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define sfstr(c) scanf("%s",c)
#define sfdl(x) scanf("%lf",&x)
#define sfll(x) scanf("%I64d",&x)
#define sfch(c) scanf("%c",&c)
#define fr(i,s,n) for(int i=s;i<n;++i)
#define cl(a) memset(a,0,sizeof(a))
int n;
const int N = 2010;const int M = 4000010;
struct Edg
{
	int u,v,nxt; 
}edg[M];	
int tote,head[N];
void init(){
	tote = 0;
	memset(head,-1,sizeof(head));
}
inline void addedg(int u,int v){
	edg[tote].u=u;edg[tote].v=v;edg[tote].nxt=head[u];head[u]=tote++;
};

struct WED{
	int s,e;
	void disp(){
		printf("%.2d:%.2d %.2d:%.2d\n",s/60,s%60,e/60,e%60);
	}
}wed[2010];

bool against(int i,int j){
	if(wed[i].s>=wed[j].e ) return 0;
	if(wed[j].s>=wed[i].e) return 0;
	return 1;
}
void build(int i ,int j){
	if(against(i<<1,j<<1)) addedg(i<<1,j<<1|1);
	if(against(i<<1,j<<1|1)) addedg(i<<1,j<<1);
	if(against(i<<1|1,j<<1)) addedg(i<<1|1,j<<1|1);
	if(against(i<<1|1,j<<1|1)) addedg(i<<1|1,j<<1);
}
int bcnt,stop,dindex;
int DFN[N],low[N],stap[N],belong[N];
bool instack[N];
void tarjan(int u){
	DFN[u]=low[u]=++dindex;instack[u]=1;stap[stop++]=u;
	for(int i=head[u];i!=-1;i=edg[i].nxt){
		int j = edg[i].v;
		if (!DFN[j]){
			tarjan(j);
			if (low[u]>low[j]) low[u]=low[j];
		}
		else if(instack[j]&&DFN[j]<low[u]) low[u]=DFN[j];
	}
	if (DFN[u]==low[u]){
		++bcnt;
		int j;
		do{
			j=stap[--stop];instack[j]=0;belong[j]=bcnt;
		}while(j!=u);
	}
}
void tarjan_find(){
	cl(DFN);
	memset(instack,0,sizeof(instack));
	stop = bcnt = dindex=0;
	fr(i,0,n*2){
		if (!DFN[i])
			tarjan(i);
	}
}

vector<int> dag[N];
int ind[N];
void makedag(){
	int v;
	fr(u ,0  ,2*n){
		for(int i = head[u];i!=-1;i = edg[i].nxt){
			v = edg[i].v;
			if (belong[u] != belong[v]){
				dag[belong[v]].push_back(belong[u]);
				++ind[belong[u]];
			}
		}
	}
}
queue<int> q;
vector<int> ha[N];
int color[N];
void topsort(){
	fr(i , 1 ,  bcnt+1){
		if(ind[i]==0){
			q.push(i);
		}
	}
	int u,v,siz;
	while(!q.empty()){
		u = q.front();
		q.pop();
		siz = dag[u].size();
		if(!color[u] ){
			color[u] = 1;
			for(int i = 0;i< ha[u].size();++i){
				color[ha[u][i]]=2;
			}
		}
		fr(i ,  0 , siz){
			v = dag[u][i];
			--ind[v];
			if(ind[v] == 0){
				q.push(v);
			}
		}
	}
}

void solve(){
	fr(i , 0 ,n){
		if(belong[2*i] == belong[2*i+1]){
			puts("NO");
			return ;
		}
		else {
			ha[belong[2 * i]].push_back(belong[2*i+1]);
			ha[belong[2 * i + 1]].push_back(belong[2*i]);
		}
	}
	puts("YES");
	makedag();
	topsort();
	fr(i , 0 ,n){
		if(color[belong[i<<1]] == 1){
			wed[i<<1].disp();
		}
		else{
			wed[i<<1|1].disp();
		}
	}
}
int main(){
	init();
	sfint(n);
	int x,y,x1,y1,d;
	fr(i , 0 ,n){
		scanf("%d:%d %d:%d %d",&x,&y,&x1,&y1,&d);
		wed[i<<1].s = x*60+y; wed[i<<1].e = wed[i<<1].s + d;
		wed[i<<1|1].e = x1*60+y1;wed[i<<1|1].s = wed[i<<1|1].e-d;
	}
	fr(i , 0 ,n){
		fr(j , 0 , n){
			if(i!=j)
			build(i,j);
		}
	}
	tarjan_find();
	solve();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值