题意:

  一些人要在同一天进行婚礼,但是牧师只有1个,每一对夫妻都有一个时间范围[s , e]可供牧师选择,且起码要m分钟才主持完毕,但是要么就在 s 就开始,要么就主持到刚好 e 结束。因为人数太多了,这些时间可能会重叠,可能还会完全包含,可能还没有交叉,各种情况。问牧师能否主持完全部人的婚礼,若可以,给出每对夫妻占用牧师的一个时间段(记得按所给的夫妻的顺序哦)。

  主要步骤如下。

(1)先建原图,不管是否会冲突。

(2)找强连通分量来缩点,如果会冲突,这个时候应该发现。

(3)建个缩点后,原图的反向图。

(4)着色法标记所要输出的时间段。

(5)时间段按照所给每对夫妻的顺序来输出。

实现:

  (1)婚礼要么在s就开始,要么在e刚好结束,还有可能这对夫妻就要求从s-e都要主持呢。 先把时间给转换成分钟,每对夫妻拥有2个时间段。

  (2)接下来主要是建图,建图时只考虑“冲突”,即如果i*2和j*2冲突了,那么选i*2就必须选j*2+1。先不用顾着i*2和j*2+1是否冲突,只要将4种可能的组合列出来,建图,其他的交给强连通分量去做。

  (3)强连通分量承接第3步的重任,在求强连通分量时要顺便判断是否会冲突,当然这比较简单。

  (4)建反向图只是穷举原图中的每条边,判断是否在同个scc中,如果不是就可以建边了,将边反过来这么简单。

  (5)着色时还得将另外冲突的“全部“着其他颜色,那么根据已建好的反向图一直DFS下去,如果已经着色,可以退出了,别每次都深搜到底了,没必要。

  (6)时间段还得按所给夫妻顺序!那得再稍微处理一下。

  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <vector>
  5. #include <stack>
  6. #include <algorithm>
  7. #define LL long long
  8. #define pii pair<int,int>
  9. #define INF 0x7f7f7f7f
  10. using namespace std;
  11. const int N=+;
  12. int t1[N], t2[N], t3[N], t4[N]; //保存时间点
  13. bool vis[N];
  14. vector<int> vect[N*], rg[N*], scc[N*]; //分别是:原图,反向图,
  15. stack<int> stac; //强连通分量必备
  16. int lowlink[N*], dfn[N*], scc_no[N*], scc_cnt, dfn_clock; //强连通分量必备
  17. int col[N*]; //用于着色
  18. bool dele[N*]; //标记输出点
  19.  
  20. inline int to_time(int h, int m){return h*+m;}
  21. inline bool conflict(int a,int b, int c, int d){if(b<=c || d<=a) return true;return false;}
  22.  
  23. void get_graph(int n) //难在建图吧?
  24. {
  25. for(int i=; i<n*; i++) vect[i].clear();
  26. for(int i=; i<n; i++)
  27. {
  28. for(int j=; j<n; j++) //考虑放在前面
  29. {
  30. if(i==j) continue;
  31. if(!conflict(t1[i],t2[i], t1[j],t2[j])) vect[i*].push_back(j*+);
  32. if(!conflict(t1[i],t2[i], t3[j],t4[j])) vect[i*].push_back(j*);
  33.  
  34. if(!conflict(t3[i],t4[i], t1[j],t2[j])) vect[i*+].push_back(j*+);
  35. if(!conflict(t3[i],t4[i], t3[j],t4[j])) vect[i*+].push_back(j*);
  36. }
  37. }
  38. }
  39.  
  40. void DFS(int x) //模板tarjan
  41. {
  42. stac.push(x);
  43. dfn[x]=lowlink[x]=++dfn_clock;
  44. for(int i=; i<vect[x].size(); i++)
  45. {
  46. int t=vect[x][i];
  47. if(!dfn[t])
  48. {
  49. DFS(t);
  50. lowlink[x]=min(lowlink[x],lowlink[t]);
  51. }
  52. else if(!scc_no[t]) lowlink[x]=min(lowlink[x],dfn[t]);
  53. }
  54. if(lowlink[x]==dfn[x])
  55. {
  56. scc[++scc_cnt].clear();
  57. while(true)
  58. {
  59. int t=stac.top();stac.pop();
  60. scc_no[t]=scc_cnt;
  61. scc[scc_cnt].push_back(t);
  62. if(t==x) break;
  63. }
  64. }
  65. }
  66.  
  67. int find_scc(int n) //求强连通分量,顺便检查是否满足条件
  68. {
  69. scc_cnt=dfn_clock=;
  70. memset(lowlink,,sizeof(lowlink));
  71. memset(dfn,,sizeof(dfn));
  72. memset(scc_no,,sizeof(scc_no));
  73. for(int i=; i<n; i++) if(!dfn[i]) DFS(i);
  74. for(int i=; i<n; i+=) if(scc_no[i]==scc_no[i+]) return false; //检查是否冲突
  75. return true;
  76. }
  77.  
  78. void build_rg(int n) //建反向图,为了要反向着色
  79. {
  80. for(int i=; i<n; i++) rg[i].clear();
  81.  
  82. for(int i=; i<n; i++)
  83. {
  84. for(int j=; j<vect[i].size(); j++)
  85. {
  86. int t=vect[i][j];
  87. if(scc_no[i]!=scc_no[t]) //不属于同个强连通分量
  88. rg[scc_no[t]].push_back(scc_no[i]);
  89. }
  90. }
  91. }
  92.  
  93. void del(int s) //删除的是反向边,之前已建好的rg图
  94. {
  95. while(!col[s])
  96. {
  97. col[s]=;
  98. for(int i=; i<rg[s].size(); i++) del(rg[s][i]); //递归“删除”,按反向边的方向(即着其他颜色)
  99. }
  100. }
  101.  
  102. void color()
  103. {
  104. memset(col,,sizeof(col));
  105. for(int i=; i<=scc_cnt; i++) //没有按照拓扑顺序也能AC???
  106. if(!col[i])
  107. {
  108. col[i]=;
  109. del( scc_no[ scc[i][]%==?scc[i][]+:scc[i][]-]); //在第i个SCC中任取1点,取其对立点,再取其所在scc编号,进行着色
  110. }
  111. }
  112.  
  113. void print(int n)
  114. {
  115. memset(dele,,sizeof(dele));
  116. puts("YES");
  117. for(int i=; i<scc_cnt; i++)
  118. {
  119. if(col[i]==) //col=2的都是要的,当然,选全部col=3也一样,因为对称
  120. for(int j=; j<scc[i].size(); j++)
  121. dele[scc[i][j] ]=true; //把所有要输出的点先标记出来
  122. }
  123. for(int i=; i<n; i++)
  124. {
  125. if(dele[i])
  126. if(i%==) //取前段
  127. {
  128. int a=t1[i/]/;
  129. int b=t1[i/]%;
  130. int c=t2[i/]/;
  131. int d=t2[i/]%;
  132. printf("%02d:%02d %02d:%02d\n",a,b,c,d);
  133. }
  134. else //取后段
  135. {
  136. int a=t3[i/]/;
  137. int b=t3[i/]%;
  138. int c=t4[i/]/;
  139. int d=t4[i/]%;
  140. printf("%02d:%02d %02d:%02d\n",a,b,c,d);
  141. }
  142. }
  143. }
  144. int main()
  145. {
  146. freopen("input.txt", "r", stdin);
  147. int n, a, b, c, d, e, f, g;
  148. while(~scanf("%d",&n))
  149. {
  150. memset(t1,,sizeof(t1));
  151. memset(t2,,sizeof(t2));
  152. memset(t3,,sizeof(t3));
  153. memset(t4,,sizeof(t4));
  154. for(int i=; i<n; i++)
  155. {
  156. scanf("%d %c %d %d %c %d %d",&a,&b,&c, &d,&e,&f, &g);
  157. t1[i]=to_time(a,c); //时间转成分钟,分别有2种,t1t2表示在前的start和end,t3t4表示在后
  158. t2[i]=to_time(a,c)+g;
  159. t3[i]=to_time(d,f)-g;
  160. t4[i]=to_time(d,f);
  161. }
  162. get_graph(n);
  163. if(!find_scc(n<<)) {puts("NO");continue;}
  164. build_rg(n*); //按缩点建新的反向图reverse_graph
  165. color(); //着色完,所需要的点也就出结果了
  166. print(n*);
  167. }
  168. return ;
  169. }

AC代码

POJ 3683 Priest John's Busiest Day (2-SAT,常规)的更多相关文章

  1. POJ 3683 Priest John's Busiest Day / OpenJ_Bailian 3788 Priest John's Busiest Day(2-sat问题)

    POJ 3683 Priest John's Busiest Day / OpenJ_Bailian 3788 Priest John's Busiest Day(2-sat问题) Descripti ...

  2. POJ 3683 Priest John's Busiest Day(2-SAT+方案输出)

    Priest John's Busiest Day Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 10010   Accep ...

  3. POJ 3683 Priest John's Busiest Day (2-SAT)

    Priest John's Busiest Day Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 6900   Accept ...

  4. POJ 3683 Priest John's Busiest Day(2-SAT 并输出解)

    Description John is the only priest in his town. September 1st is the John's busiest day in a year b ...

  5. poj - 3683 - Priest John's Busiest Day(2-SAT)

    题意:有N场婚礼,每场婚礼的开始时间为Si,结束时间为Ti,每场婚礼有个仪式,历时Di,这个仪式要么在Si时刻开始,要么在Ti-Di时刻开始,问能否安排每场婚礼举行仪式的时间,使主持人John能参加所 ...

  6. POJ 3683 Priest John's Busiest Day (2-SAT)

    题意:有n对新人要在同一天结婚.结婚时间为Ti到Di,这里有时长为Si的一个仪式需要神父出席.神父可以在Ti-(Ti+Si)这段时间出席也可以在(Di-Si)-Si这段时间.问神父能否出席所有仪式,如 ...

  7. POJ 3683 Priest John's Busiest Day

    2-SAT简单题,判断一下两个开区间是否相交 #include<cstdio> #include<cstring> #include<cmath> #include ...

  8. POJ 3683 Priest John's Busiest Day[2-SAT 构造解]

    题意: $n$对$couple$举行仪式,有两个时间段可以选择,问是否可以不冲突举行完,并求方案 两个时间段选择对应一真一假,对于有时间段冲突冲突的两人按照$2-SAT$的规则连边(把不冲突的时间段连 ...

  9. POJ 3683 Priest John's Busiest Day 【2-Sat】

    这是一道裸的2-Sat,只要考虑矛盾条件的判断就好了. 矛盾判断: 对于婚礼现场 x 和 y,x 的第一段可以和 y 的第一段或者第二段矛盾,同理,x 的第二段可以和 y 的第一段或者第二段矛盾,条件 ...

随机推荐

  1. Perl中的正则表达

    前几天用到了Perl语言,主要看了一下Perl中的正则表达式,在各种网页语言中,正则表达式在处理字符串的时候十分有用,所以这里就简单说一下在Perl中正则表达式的应用. 先上代码 #!/usr/bin ...

  2. dom树的介绍,及原理分析

    三.解析和DOM树的构建 1.解析: 由于解析渲染引擎是一个非常重要的过程,我们将会一步步的深入,现在让我们来介绍解析. 解析一个文档,意味着把它转换为一个有意义的结构——代码可以了解和使用的东西,解 ...

  3. The method of type must override a superclass method

    导入android项目时,报The method of type must override asuperclass method 一堆错误, 解决方法: 将编译的jdk与使用的jdk版本一致即可.

  4. Kinetic使用注意点--ellipse

    new Ellipse(config) 参数: config:包含所有配置项的对象. { radius: "半径,可以用数字a.数组[a,b]或对象{x:a,y:b}来表示" } ...

  5. gridView AspNetPager 翻页时 弹出窗体关闭报错

    gridView AspNetPager 翻页后,你右击刷新或F5会发现弹出一个刷新页面. 这是因为默认翻页都是用dopostback方式回发的.因为这时的页面已经不是原来的页面.所以会弹出提示. 这 ...

  6. EXTJS4.2 控件之Grid 行点击事件

    listeners: { 'itemclick': function (view, record, item, index, e) { //Ext.MessageBox.alert("标题& ...

  7. 滤镜简单demo(转,供参考)

    NSURL *iamgeUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"default" ...

  8. ng-blur失去焦点执行事件

    <label class="item item-input item-stacked-label"> <span class="input-label& ...

  9. 团体程序设计天梯赛-练习集L1-011. A-B

    L1-011. A-B 时间限制 100 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 本题要求你计算A-B.不过麻烦的是,A和B都是字符串 — ...

  10. uva 1103

    弄懂题意后  其实就是一个dfs /************************************************************************* > Aut ...