POJ-3683-Priest John's Busiest Day(2-sat)
POJ 2-sat六题之三
http://blog.sina.com.cn/s/blog_64675f540100k1cd.html
题目描述:有n个婚礼,每个婚礼有起始时间si,结束时间ti,还有一个主持时间ti,ti必须安排在婚礼的开始或者结束,主持由祭祀来做,但是只有一个祭祀,所以各个婚礼的主持时间不能重复,问你有没有可能正常的安排主持时间,不能输出no,能的话要输出具体的答案:即每个婚礼的主持时间段是什么样的。
解题报告:
对于每个婚礼,主持时间只有两种状态,而且各个婚礼之间的主持时间之间有相互限制,所以想到2-sat。
构图:
对于婚礼i和婚礼j。i表示在开始主持,i2表示在结束主持,j类似。
枚举每一对不同的i和j。
如果i和j冲突。连接i j2
如果i和j2冲突,连接i j
如果i2和j冲突,连接i2 j2
如果i2和j2冲突,连接i2 j
// File Name: 3683.cpp // Author: zlbing // Created Time: 2013/1/30 13:43:55 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> using namespace std; #define MAXN 1050 int T[MAXN][3]; struct TwoSAT{ int n; vector<int>G[MAXN*2]; bool mark[MAXN*2]; stack<int>S; bool dfs(int x) { if(mark[x^1])return false; if(mark[x])return true; mark[x]=true; S.push(x); for(int i=0;i<G[x].size();i++) { int v=G[x][i]; if(!dfs(v))return false; } return true; } void init(int _n) { n=_n; for(int i=0;i<2*n;i++) G[i].clear(); memset(mark,0,sizeof(mark)); } /* void add_clause(int x,int xval,int y,int yval) { x=x*2+xval; y=y*2+yval; G[x^1].push_back(y); G[y^1].push_back(x); } */ void add_clause(int x,int y) { G[x].push_back(y); } bool solve() { for(int i=0;i<2*n;i=i+2) { if(!mark[i]&&!mark[i+1]){ while(!S.empty()) { S.pop(); } if(!dfs(i)) { while(!S.empty()) { mark[S.top()]=false; S.pop(); } if(!dfs(i+1))return false; } } } printf("YES\n"); int e; for(int i=0;i<2*n;i++) if(mark[i]){ int j=T[i/2][i%2]; if(i%2)e=-T[i/2][2]; else e=T[i/2][2]; if(i&1) printf("%02d:%02d %02d:%02d\n",(j+e)/60,(j+e)%60,j/60,j%60); else printf("%02d:%02d %02d:%02d\n",j/60,j%60,(j+e)/60,(j+e)%60); } return true; } }; TwoSAT solver; int main(){ int n; while(~scanf("%d",&n)) { solver.init(n); for(int i=0;i<n;i++) { int a,b; scanf("%d:%d",&a,&b); a=a*60+b; int c,d; scanf("%d:%d",&c,&d); c=c*60+d; int e; scanf("%d",&e); T[i][0]=a,T[i][1]=c,T[i][2]=e; } for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) { if(i==j)continue; if(T[j][0]+T[j][2]>T[i][0]&&T[i][0]+T[i][2]>T[j][0]) solver.add_clause(i*2,2*j+1); if(T[j][1]>T[i][0]&&T[i][0]+T[i][2]>T[j][1]-T[j][2]) solver.add_clause(i*2,2*j); if(T[j][0]+T[j][2]>T[i][1]-T[i][2]&&T[i][1]>T[j][0]) solver.add_clause(i*2+1,2*j+1); if(T[j][1]>T[i][1]-T[i][2]&&T[i][1]>T[j][1]-T[j][2]) solver.add_clause(i*2+1,2*j); } if(!solver.solve()) printf("NO\n"); } return 0; }