POJ 3683 Priest John's Busiest Day(2-SAT输出方案)
http://poj.org/problem?id=3683
题意:
有N对新人举行婚礼,且每次婚礼需要持续d时间,从s时间到t时间之间举行且只能选择s到s+d时间或t-d到t时间这两个完整的时间段举行.现在只有一个神父,问他有没有可能参加所有新人的婚礼(待完整段时间且任意两对新人的婚礼时间不重叠)? 输出一个可行的方案.
分析:
每对新人的婚礼时间只有两种选择,直接就可以转化为2-SAT问题.其中如果对于第i个婚礼与第j个婚礼来说:
假设i先办的时间区间为[a,b]而j后办的时间区间为[c,d],如何判断[a,b]与[c,d]是否发生了冲突呢?(边界相交不算).
只有下面两种情况下区间[s1,e1]与区间[s2,e2]才规范相交.
1. s1<e2 且 s2<e1
2. s2<e1 且 s1<e2
仔细一看上面两种情况是相同的,只要相交的两个区间的e1 e2 > s1 s2 即可保证这两个区间相交.
(仔细想想上面情况)
然后对于冲突的每对新人添加边即可.
AC代码:
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=1000+10;
struct Time
{
int s,e,d;//开始,结束,持续
Time(){}
Time(int s,int e,int d):s(s),e(e),d(d){}
}t[maxn];
struct TwoSAT
{
int n;
vector<int> G[maxn*2];
int S[maxn*2],c;
bool mark[maxn*2];
bool dfs(int x)
{
if(mark[x^1]) return false;
if(mark[x]) return true;
mark[x]=true;
S[c++]=x;
for(int i=0;i<G[x].size();i++)
if(!dfs(G[x][i])) return false;
return true;
}
void init(int n)
{
this->n=n;
for(int i=0;i<n*2;i++) G[i].clear();
memset(mark,0,sizeof(mark));
}
void add_clause(int x,int xval,int y,int yval)//这里做了修改,指x与y值有冲突
{
x=x*2+xval;
y=y*2+yval;
G[x].push_back(y^1);
G[y].push_back(x^1);
}
bool solve()
{
for(int i=0;i<2*n;i+=2)if(!mark[i] && !mark[i+1])
{
c=0;
if(!dfs(i))
{
while(c>0) mark[S[--c]]=false;
if(!dfs(i+1)) return false;
}
}
return true;
}
}TS;
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
int sh,sm,eh,em,d;
scanf("%d:%d %d:%d %d",&sh,&sm,&eh,&em,&d);
t[i]=Time(sh*60+sm,eh*60+em,d);
}
TS.init(n);
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
{
if(t[i].s < t[j].s+t[j].d && t[j].s < t[i].s+t[i].d )
TS.add_clause(i,0,j,0);
if(t[i].s < t[j].e && t[j].e-t[j].d < t[i].s+t[i].d )
TS.add_clause(i,0,j,1);
if(t[i].e-t[i].d < t[j].s+t[j].d && t[j].s < t[i].e)
TS.add_clause(i,1,j,0);
if(t[i].e-t[i].d < t[j].e && t[j].e-t[j].d < t[i].e)
TS.add_clause(i,1,j,1);
}
if(!TS.solve()) printf("NO\n");
else
{
printf("YES\n");
for(int i=0;i<n;i++)
{
if(TS.mark[i*2])
printf("%02d:%02d %02d:%02d\n",t[i].s/60,t[i].s%60,(t[i].s+t[i].d)/60,(t[i].s+t[i].d)%60);
else
printf("%02d:%02d %02d:%02d\n",(t[i].e-t[i].d)/60,(t[i].e-t[i].d)%60,t[i].e/60,t[i].e%60);
}
}
return 0;
}