POJ 3683 Priest John's Busiest Day

题目链接:http://poj.org/problem?id=3683

题目描述:

    有一个牧师需要给n对新婚夫妇举行婚礼,每对夫妇有两个时间段进行选择,问该牧师能否给所有的夫妇举行婚礼。

     这就属于一道比较模板的2-SAT题,可以直接用模板解即可。

    关于更多2-SAT的介绍,可以参考:

    http://blog.csdn.net/dg_programming/article/details/38875861

      http://www.cnblogs.com/kuangbin/archive/2012/10/05/2712429.html

    

#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std ;

const int MAXN = 1005 ;
const int MAXV = 2005 ;
int V, n ;
vector<int> G[MAXV], rG[MAXV] ;
vector<int> vs ;
int cmp[MAXV] ;
bool used[MAXV] ;
int s[MAXN], t[MAXN], d[MAXN] ; //记录读入数据

void addEdge(int from, int to){
	G[from].push_back(to) ;
	rG[to].push_back(from) ;
}
//正向
void dfs(int t){
	used[t] = true ;
	for( int i = 0; i < G[t].size(); i++ ){
		if( !used[G[t][i]] )	dfs(G[t][i]) ;
	}
	vs.push_back(t) ;
}
//反向
void rdfs(int t, int k){
	used[t] = true ;
	cmp[t] = k ;
	for( int i = 0; i < rG[t].size(); i++ ){
		if( !used[rG[t][i]] )	rdfs(rG[t][i],k) ;
	} 
}
//
int scc(){
	memset(used,false,sizeof(used)) ;
	memset(cmp,0,sizeof(cmp)) ;
	vs.clear() ;
	for( int i = 0; i < V; i++ ){
		if( !used[i] )	dfs(i) ;
	}
	memset(used,false,sizeof(used)) ;
	int k = 0 ;
	for( int i = vs.size()-1; i >= 0; i-- ){
		if( !used[vs[i]] )	rdfs(vs[i],k++) ;
	}
	return k ;
}
//
void twoSAT(){
	V = 2*n ;
	for( int i = 0; i < V; i++ ){
		G[i].clear(), rG[i].clear() ;
	}
	for( int i = 0; i < n; i++ ){
		for( int j = 0; j < i; j++ ){
			//(i+n) V (j+n),当i,j有交集的时候
			if( min(s[i]+d[i],s[j]+d[j]) > max(s[i],s[j]) ){
				addEdge(i,j+n) ;
				addEdge(j,i+n) ;		
			}
			if( min(t[i],t[j]) > max(t[i]-d[i],t[j]-d[j]) ){
				addEdge(i+n,j) ;
				addEdge(j+n,i) ;
			}
			if( min(s[i]+d[i],t[j]) > max(s[i],t[j]-d[j]) ){
				addEdge(i,j) ;
				addEdge(j+n,i+n) ;
			}
			if( min(t[i],s[j]+d[j]) > max(t[i]-d[i],s[j]) ){
				addEdge(i+n,j+n) ;
				addEdge(j,i) ;
			}
		}
	}
	scc() ;
	for( int i = 0; i < n; i++ ){
		if( cmp[i] == cmp[i+n] ){
			puts("NO") ;
			return ;
		}
	}
	puts("YES") ;
	for( int i = 0; i < n; i++ ){
		//i为true
		if( cmp[i] > cmp[i+n] ){
			printf("%02d:%02d %02d:%02d\n",s[i]/60,s[i]%60,(s[i]+d[i])/60,(s[i]+d[i])%60) ;		
		}else{
			printf("%02d:%02d %02d:%02d\n",(t[i]-d[i])/60,(t[i]-d[i])%60,t[i]/60,t[i]%60) ;		
		}
	}
}
//
void cal(){
	char tmp[8] ;
	for( int i = 0; i < n; i++ ){
		scanf("%s",tmp) ;
		s[i] = (tmp[0]-'0')*600 + (tmp[1]-'0')*60 + (tmp[3]-'0')*10 + (tmp[4]-'0') ;
		scanf("%s",tmp) ;
		t[i] = (tmp[0]-'0')*600 + (tmp[1]-'0')*60 + (tmp[3]-'0')*10 + (tmp[4]-'0') ;
		scanf("%d",&d[i]) ;
	}
	twoSAT() ;
}
//
int main(){
//	freopen("1234.in","r",stdin) ;
	while( scanf("%d",&n) != EOF ){		
		cal() ;
	}
	
	return 0 ;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值