题目链接:http://poj.org/problem?id=3683
题意:每个婚礼有两个时段(婚礼开始,或者结束)可以进行特别仪式,特别仪式必须要有神父在场,神父只有一个,问是否能满足所有婚礼的需求。
规模:( 1 ≤ N ≤ 1000),N场婚礼
类型: 2-sat
分析:这是“大白书”上的2-sat基础。
每场婚礼都只有两个时间段,而且不能冲突,是2-sat的典型模型。
我们将所有不能共存的关系列出,据此建边,跑2-sat就行了。
这里稍微解释一下建边过程:
对于两场婚礼a,b
用a表示“婚礼开始时举行仪式”,用(!a)表示“婚礼结束时举行仪式”,b同a;
那么我们有四种组合方式:
(a,b),(a,!b),(!a,b),(!a,!b)
对于每组确定的a,b,我们可以得到这四种组合是否成立。
因为求的是2-sat,我们只需要对冲突的组合建边:
时间复杂度&&优化:
代码:
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
using namespace std;
const int MAXN=2005;
const int MAXM=40000000;
int n;
struct Time{
int s,t;
int l;
}time[MAXN];
struct Edge{
int to,next;
}edge[MAXM];
int head[MAXN],tot;
void init(){
tot=0;
memset(head,-1,sizeof(head));
}
void add_edge(int u,int v){
edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++;
}
void ADD(int i,int j){
Time a=time[i];
Time b=time[j];
if(min(a.s+a.l,b.s+b.l)>max(a.s,b.s)){
//a=>!b,b=>!a
add_edge((2*i),(2*j)^1);
add_edge((2*j),(2*i)^1);
}
if(min(a.s+a.l,b.t)>max(a.s,b.t-b.l)){//cout<<2;
add_edge((2*i),2*j);
add_edge((2*j)^1,(2*i)^1);
}
if(min(a.t,b.s+b.l)>max(a.t-a.l,b.s)){//cout<<3;
add_edge((2*i)^1,(2*j)^1);
add_edge(2*j,2*i);
}
if(min(a.t,b.t)>max(a.t-a.l,b.t-b.l)){//cout<<4;
add_edge((2*i)^1,2*j);
add_edge((2*j)^1,2*i);
}
}
bool vis[MAXN];
int S[MAXN],top;
bool dfs(int u){
if(vis[u^1])return false;
if(vis[u])return true;
vis[u]=true;
S[top++]=u;
for(int i=head[u];i!=-1;i=edge[i].next){
if(!dfs(edge[i].to))
return false;
}
return true;
}
bool Twosat(int n){
memset(vis,false,sizeof(vis));
for(int i=0;i<n;i+=2){
if(vis[i]||vis[i^1])continue;
top=0;
if(!dfs(i)){
while(top)vis[S[--top]]=false;
if(!dfs(i^1))return false;
}
}
return true;
}
void solve(){
if(Twosat(2*n)){
printf("YES\n");
for(int i = 0;i < n;i++)
if(vis[i*2]){
printf("%02d:%02d %02d:%02d\n",time[i].s/60,time[i].s%60,(time[i].s+time[i].l)/60,(time[i].s+time[i].l)%60);
}
else{
printf("%02d:%02d %02d:%02d\n",(time[i].t-time[i].l)/60,(time[i].t-time[i].l)%60,time[i].t/60,time[i].t%60);
}
return;
}
printf("NO\n");
}
int main()
{
while(scanf("%d",&n)==1){
init();
for(int i=0;i<n;i++){
int a,b,c;
scanf("%d:%d",&a,&b);
time[i].s=a*60+b;
scanf("%d:%d",&a,&b);
time[i].t=a*60+b;
scanf("%d",&time[i].l);
}
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
ADD(i,j);
}
}
// for(int i=0;i<2*n;i++){
// cout<<i<<endl;
// for(int j=head[i];j!=-1;j=edge[j].next)
// printf("%d ",edge[j].to);
// cout<<endl;
// }
solve();
}
return 0;
}
本文介绍了一种使用2-SAT算法解决婚礼仪式调度问题的方法,确保单一神父能在不同时段为多场婚礼进行特别仪式,避免时间冲突。通过建立合适的图模型并运行2-SAT算法来验证解决方案的可行性。
2324

被折叠的 条评论
为什么被折叠?



