题意

有一个小镇上只有一个牧师。这个小镇上有一个传说,在九月一日结婚的人会受到爱神的保佑,但是要牧师举办一个仪式。这个仪式要么在婚礼刚刚开始的时候举行,要么举行完婚礼正好结束。
现在已知有n场婚礼,告诉你每一场的开始和结束时间,以及举行仪式所需要的时间。问牧师能否参加所有的婚礼,如果能则输出一种方案。

题解

2-SAT + 路径输出
首先建图不难,判断两个时间段是否相交。
然后按照tarjan缩点,跑一边逆拓扑排序,按照逆序的结果开始选择,并把它的对称点删掉。求出来的就是结果。
逆拓扑排序直接把缩点后的图边反向建立,然后跑一边正的拓扑排序就好了。
注意输出的时候要按照原来婚礼的顺序进行输出。

代码

#include<cstdio>
#include<queue>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 1e6+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
int tot, head[10005], nhead[10005], tot2;
int n;
struct edge{int to, nxt;
}e[nmax<<1], ng[nmax<<1];
void add_edge(int u, int v) {e[tot].to = v;e[tot].nxt = head[u];head[u] = tot++;
}
void add_edge2(int u, int v) {ng[tot2].to = v;ng[tot2].nxt = nhead[u];nhead[u] = tot2++;
}
struct Node{int st1, st2, last;
}node[10005];
int dfn[10005], low[10005], ss[10005], st, scc_cnt, color[10005], in[10005], dfs_clock;
int belong[10005], oppcolor[10005];
bool instack[10005], ban[10005];
vector<int> scc[10005];
queue<int> q;
void init() {tot2 = scc_cnt = st = dfs_clock = tot = 0 ;while(!q.empty()) q.pop();memset(head, -1, sizeof head);memset(nhead, -1, sizeof nhead);memset(dfn, 0, sizeof dfn);memset(low, 0, sizeof low);memset(color, 0, sizeof color);memset(ban, 0 ,sizeof ban);memset(belong, 0, sizeof belong);memset(in, 0, sizeof in);memset(oppcolor, 0, sizeof oppcolor);
}
void tarjan(int u) {dfn[u] = low[u] = ++ dfs_clock;ss[st++] = u;instack[u] = true;for(int i = head[u]; i != -1; i = e[i].nxt) {int v = e[i].to;if(!dfn[v]) {tarjan(v);low[u] = min(low[u], low[v]);} else if(instack[v]) {low[u] = min(low[u], dfn[v]);}}if(low[u] == dfn[u]) {scc_cnt++;scc[scc_cnt].clear();int tmp;while(1) {tmp = ss[--st];color[tmp] = scc_cnt;scc[scc_cnt].push_back(tmp);instack[tmp] = false;if(tmp == u)break;}}
}
void toposort(int u) {q.push(u);in[u] = -1;for(int i = nhead[u]; i != -1; i = ng[i].nxt) {int v = ng[i].to;in[v] --;if(!in[v])toposort(v);}
}
bool notcross(int as, int ae, int bs, int be) {if(be <= as || bs >= ae)return true;elsereturn false;
}
void dfs(int u) {ban[u] = 2;for(int i = nhead[u]; i != -1; i = ng[i].nxt) {int v = ng[i].to;if(ban[v] == 0)dfs(v);}
}
void show(int hour, int minute) {if(hour < 10) printf("0%d:",hour);else printf("%d:",hour);if(minute < 10) printf("0%d",minute);else printf("%d",minute);
}
int main(){while(scanf("%d", &n) != EOF) {init();int sth, stm, edh, edm , last;for(int i = 1; i <= n; ++i) {scanf("%d", &sth);getchar();scanf("%d %d", &stm, &edh);getchar();scanf("%d %d", &edm, &last);node[i].st1 = sth * 60 + stm;node[i].st2 = edh * 60 + edm - last;node[i].last = last;}for(int i = 1; i <= n; ++i) {for(int j = i + 1; j <= n; ++j) {if(!notcross(node[i].st1 , node[i].st1 + node[i].last, node[j].st1, node[j].st1 + node[j].last)) {add_edge(i, j + n);add_edge(j, i + n);}if(!notcross(node[i].st2 ,node[i].st2 + node[i].last, node[j].st1, node[j].st1 + node[j].last)) {add_edge(i + n, j + n);add_edge(j, i);}if(!notcross(node[i].st1, node[i].st1 + node[i].last, node[j].st2, node[j].st2 + node[j].last)) {add_edge(i, j);add_edge(j + n, i + n);}if(!notcross(node[i].st2, node[i].st2 + node[i].last, node[j].st2, node[j].st2+ node[j].last)) {add_edge(i + n, j);add_edge(j + n, i);}}}for(int i = 1; i <= 2* n; ++i) {if(!dfn[i]) {tarjan(i);}}bool isok = true;for(int i = 1; i <= n; ++i) {if(color[i] == color[i + n]) {isok = false;break;}}if(!isok) {printf("NO\n");continue;} elseprintf("YES\n");for(int u = 1; u <= 2 * n; ++u) {for(int i = head[u]; i != -1; i = e[i].nxt) {int v = e[i].to;if(color[u] != color[v]) {add_edge2(color[v], color[u]);in[color[u]] ++;}}if(u <= n) oppcolor[color[u]] = color[u + n];else oppcolor[color[u]] = color[u - n];}for(int i = 1; i <= scc_cnt; ++i) {if(!in[i])toposort(i);}for(int j = 1; j <= scc_cnt; ++j){int now = q.front();q.pop();if(ban[now] == 0) {ban[now] = 1;ban[oppcolor[now]] = 2;for(int i = 0; i < scc[now].size(); ++i) {belong[scc[now][i]] = 1;}}}for(int i = 1; i <= n; ++i) {if(belong[i] == 1) {show(node[i].st1 / 60 , node[i].st1 % 60);printf(" ");show( (node[i].st1 + node[i].last) / 60, (node[i].st1 + node[i].last) % 60);printf("\n");} else {show(node[i].st2 / 60 , node[i].st2 % 60);printf(" ");show( (node[i].st2 + node[i].last) / 60, (node[i].st2 + node[i].last) % 60);printf("\n");}}}return 0;
}

【算法练习】POJ - 3683 Priest John's Busiest Day (2-SAT)相关推荐

  1. [题解]POJ 3683 Priest John's Busiest Day

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

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

    题目链接:http://poj.org/problem?id=3683 题意:有n个婚礼要举行,但是只有一个牧师.第i个婚礼使用牧师的时间长为leni,可以在开始时或结束时使用.问能否使得n个婚礼均举 ...

  3. POJ - 3683 Priest John's Busiest Day(2-SAT+路径打印)

    题目链接:点击查看 题目大意:现在有n对新人要结婚,每一场婚礼都要请牧师主持一个特殊的仪式,这个仪式必须在婚礼的前d分钟或者最后d分钟进行,现在问能否有一种安排,能让牧师参加到每一场婚礼去主持仪式,输 ...

  4. POJ 3683 Priest John's Busiest Day (算竞进阶习题)

    2-SAT 可以把每一次仪式看成变量,0/1的取值分别为开头举行和结尾举行. 转换为2-SAT接受的命题,就是看某一次仪式中有没有重合的时间段,有的话,就按照不冲突的形式连有向边. 然后跑tarjan ...

  5. POJ 3683 Priest John's Busiest Day

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

  6. pku 3683 Priest John's Busiest Day 2-sat判断有误解+输出可行解

    http://poj.org/problem?id=3683 题意: 一个教父,在一天中要给n对新婚夫妇举行婚礼.已知每对夫妇举行婚礼的起始时间Si和终止时间Ti ,教父送祝福的时间要么在Si-> ...

  7. poj3683 Priest John's Busiest Day

    输出方案的2-sat 直接比较两个点强联通分量的编号,缩完点的图应该是有向无环图,根据原始做法是反图topsort出解,编号小的说明顺序在后,选择这个点符合定义. #include<cstdio ...

  8. LA 4328 Priest John's Busiest Day (Greedy)

    https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_probl ...

  9. 【2-SAT初学+模板题讲解】POJ3683 Priest John's Busiest Day

    什么是2-SAT? SAT是适定性(Satisfiability)问题的简称 .一般形式为k-适定性问题,简称 k-SAT. 可以证明,当k>2时,k-SAT是NP完全的.因此一般讨论的是k=2 ...

  10. [2-sat专练]poj 3683,hdu 1814,hdu 1824,hdu 3622,hdu 4115,hdu 4421

    文章目录 Priest John's Busiest Day code Peaceful Commission code Let's go home code Bomb Game code Elimi ...

最新文章

  1. tcp传输中的序列号
  2. 工具的特性_16 个好用的 Code Review 工具
  3. C++ Primer章课后编程问题
  4. 警钟 | 还不会Spring Boot集成JWT,你可能错过了大厂的Office了
  5. 模拟太阳系的html,纯HTML5制作的震撼太阳系网页
  6. 谷歌 Compute Engine 的虚拟机曝0day未修复,可遭接管
  7. asp.net—单例模式
  8. 为什么用格式刷不能复制行距_如何使用格式刷在PowerPoint中复制格式
  9. 编写java判断闰年_Java 判断闰年代码实例
  10. Tensorflow详解 命令行参数flags
  11. MFC 中PreTranslateMessage(MSG* pMsg)截获按钮和编辑框的消息进行预处理
  12. 2019双十一自动领喵币
  13. JAVA——JAVA知识点集锦(上)
  14. 火狐资产2.6浏览器 下载_通过浏览器体验资产商店!
  15. 《Java零基础入门到精通(集合,泛型,IO,反射,JVM, 源码)【渡一教育】》思维导图版笔记(完结)
  16. 直播电商,小红书的商业化“解药”?
  17. 机房气体灭火防护改造
  18. 七个合法学习黑客技术的网站,让你从萌新成为大佬
  19. 使用Hbuilder打包前端网站为WebApp(Android,ios应用)
  20. 苹果wifi网速慢怎么办_手机输入3个数字,wifi速度就瞬间飞起来

热门文章

  1. 【JS】使用jQuery制作图片手风琴效果
  2. matlab linux x11 display,Xming安裝 + X11-Forwarding使用
  3. awesome-git 中文版,收集常用 Git 教程、工具 の 资源库
  4. 数据湖和数据仓库的区别是什么?
  5. 对不起,这5类人都不适合自学编程
  6. revit二次开发 创建标注标记
  7. [喷嚏]区块链已落地30个场景 商用时代正在加速来临
  8. 朋友,我真诚的劝你别网贷
  9. Mobento:能搜索视频中说过的话
  10. RK3399调试支持以太网