博客
关于我
POJ 3683 Priest John's Busiest Day (算竞进阶习题)
阅读量:804 次
发布时间:2023-03-03

本文共 3390 字,大约阅读时间需要 11 分钟。

2-SAT问题的解决方法

在这个问题中,我们需要判断一系列仪式是否存在时间上的冲突。每个仪式可以看作是一个变量,其值可以是0(不举行)或1(举行)。通过将这些变量转化为2-SAT问题,我们可以利用图论中的强连通分量(SCC,Strongly Connected Component)概念来解决冲突问题。

问题转化为2-SAT

将每个仪式的时间段转化为2-SAT中的变量及其约束条件。具体来说:

  • 时间段表示:每个仪式的时间可以用开始时间和结束时间表示。例如,仪式i的时间为 [S_i, E_i],其中 S_i 和 E_i 分别表示开始时间和结束时间。
  • 变量表示:将每个仪式的时间段转化为两个变量:
    • 变量0表示仪式在某个时间段开始。
    • 变量1表示仪式在某个时间段结束。
  • 冲突检测:通过检查两个仪式的时间段是否存在重叠,若有重叠则表示这两个仪式存在冲突。根据冲突的性质,构建2-SAT图中的边。
  • 通过上述步骤,我们可以将问题转化为一个2-SAT问题,接下来需要使用Tarjan算法来处理这个问题。

    Tarjan算法的应用

    Tarjan算法是一种深度优先搜索算法,用于找到图中的强连通分量(SCC)。在2-SAT问题中,强连通分量的划分可以帮助我们判断变量之间的依赖关系。

    步骤说明

  • 数据结构准备

    • 定义节点数 n 和边数 m
    • 使用数组 headedge 来表示图的邻接表。
  • 边的添加

    • 对于每对仪式i和j,检查它们的时间段是否存在重叠。如果有重叠,则在2-SAT图中添加边。
  • Tarjan算法执行

    • 从未访问的节点开始,执行深度优先搜索,记录每个节点的发现时间 dfn 和低点时间 low
    • 在完成递归后,标记当前强连通分量。
  • 冲突检测

    • 比较每个节点i和i+n的SCC是否相同。如果相同,则说明存在冲突。
  • 结果判断

    • 如果所有节点的SCC与其对应的节点+n的SCC不同,则说明所有仪式的时间段互不冲突。
    • 否则,存在冲突,返回“NO”;否则返回“YES”。
  • 代码实现

    #include 
    #include
    #include
    #include
    using namespace std;#define INF 0x3f3f3f3f#define full(a, b) memset(a, b, sizeof(a))#define lcm(a, b) (a / gcd(a, b)) * btemplate
    inline T fpow(T x, T p, T lyd) { T ans = 1; for (; p > 0; p >>= 1, x = (x * x) % lyd) { if (p & 1) { ans = (ans * x) % lyd; } } return ans;}const int N = 5000;int n, cnt, k, tot, head[N], S[N], T[N], D[N], dfn[N], low[N], scc[N], val[N];bool ins[N];struct Edge { int v, next;};stack
    st;void addEdge(int a, int b) { edge[cnt].v = b; edge[cnt].next = head[a]; head[a] = cnt++;}bool overlap(int a, int b, int c, int d) { return (a >= c && a < d) || (b > c && b <= d) || (a <= c && b >= d);}void build() { while (!st.empty()) st.pop(); full(head, -1), full(dfn, 0), full(low, 0); full(scc, 0), full(val, 0); cnt = k = tot = 0;}void tarjan(int s) { dfn[s] = low[s] = ++k; ins[s] = true; st.push(s); for (int i = head[s]; i != -1; i = edge[i].next) { int u = edge[i].v; if (!dfn[u]) { tarjan(u); low[s] = min(low[s], low[u]); } else if (ins[u]) { low[s] = min(low[s], dfn[u]); } } if (dfn[s] == low[s]) { tot++; int cur; do { cur = st.top(); st.pop(); ins[cur] = false; scc[cur] = tot; } while (cur != s); }}int main() { while (~scanf("%d", &n)) { build(); int a, b, c, d; for (int i = 1; i <= n; i++) { scanf("%d:%d %d:%d %d", &a, &b, &c, &d, &D[i]); S[i] = a * 60 + b; T[i] = c * 60 + d; } for (int i = 1; i < n; i++) { for (int j = i + 1; j <= n; j++) { if (overlap(S[i], S[i] + D[i], S[j], S[j] + D[j])) { addEdge(i, j + n), addEdge(j, i + n); } if (overlap(S[i], S[i] + D[i], T[j] - D[j], T[j])) { addEdge(i, j), addEdge(j + n, i + n); } if (overlap(T[i] - D[i], T[i], S[j], S[j] + D[j])) { addEdge(i + n, j + n), addEdge(j, i); } if (overlap(T[i] - D[i], T[i], T[j] - D[j], T[j])) { addEdge(i + n, j), addEdge(j + n, i); } } } for (int i = 1; i <= 2 * n; i++) { if (!dfn[i]) { tarjan(i); } } bool good = true; for (int i = 1; i <= n; i++) { if (scc[i] == scc[i + n]) { good = false; break; } } if (!good) { printf("NO\n"); } else { printf("YES\n"); for (int i = 1; i <= n; i++) { val[i] = (scc[i] > scc[i + n]); if (!val[i]) { printf("%02d:%02d %02d:%02d\n", S[i] / 60, S[i] % 60, (S[i] + D[i]) / 60, (S[i] + D[i]) % 60); } else { printf("%02d:%02d %02d:%02d\n", (T[i] - D[i]) / 60, (T[i] - D[i]) % 60, T[i] / 60, T[i] % 60); } } } } return 0;}

    总结

    通过将时间冲突问题转化为2-SAT问题,并利用Tarjan算法进行强连通分量分析,我们可以有效地判断一系列仪式是否存在时间上的冲突。这种方法不仅简化了问题的复杂性,还提供了一个高效的解决方案。

    转载地址:http://kbxfk.baihongyu.com/

    你可能感兴趣的文章
    python 在包含类似字符\x16、\x12、\x某某的数组中将以\x开头的字符找出来的方法
    查看>>
    Python 在并行进程之间共享字典
    查看>>
    Python 垃圾收集器文档
    查看>>
    python 基于 wordcloud + jieba + matplotlib 生成词云
    查看>>
    python 基于detectron或mask_rcnn的mask遮罩区域进行图片截取
    查看>>
    Python编程:Tkinter图形界面设计(2)
    查看>>
    Python 基础 - Day 5 Learning Note - 模块 之 标准库:time (1)
    查看>>
    Python 基础一
    查看>>
    python 基础操作知识整理总结
    查看>>
    Python 基础知识点整理与分享,期盼你的交流!
    查看>>
    python 基础第七篇
    查看>>
    Python编程:Tkinter图形界面设计(1)
    查看>>
    Python 基础语法:None
    查看>>
    Python 基础语法:基本数据类型(一)
    查看>>
    python编程读取写入excel_Python读取txt内容写入xls格式excel中的方法
    查看>>
    Python 基础语法:基本数据类型(字典)
    查看>>
    Python 基础语法:基本数据类型(字符串)
    查看>>
    Python 基础语法:基本数据类型(集合)
    查看>>
    Python编程的终极十大工具
    查看>>
    python 堆排序
    查看>>