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

本文共 3419 字,大约阅读时间需要 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)) * b
    template
    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/

    你可能感兴趣的文章
    Plotly:如何向烛台图添加交易量
    查看>>
    Plotly:如何在 plotly express 中找到趋势线的系数?
    查看>>
    Plotly:如何在桑基图中设置节点位置?
    查看>>
    Plotly:如何处理重叠的颜色条和图例?
    查看>>
    Plotly:如何手动设置 plotly express 散点图中点的颜色?
    查看>>
    Plotly:如何结合 make_subplots() 和 ff.create_distplot()?
    查看>>
    Plotly:如何绘制累积的“步骤“;直方图?
    查看>>
    Quartz进一步学习与使用
    查看>>
    Plotly条形图-根据正/负值更改颜色-python
    查看>>
    PLSQL developer12安装图解
    查看>>
    PLSQL Developer调试 存储过程和触发器
    查看>>
    PLSQL window操作
    查看>>
    plsql 存储过程 测试
    查看>>
    plsql 安装后database下拉没有东西
    查看>>
    PLSQL_Oracle PLSQL内置函数大全(概念)
    查看>>
    PLSQL_案例优化系列_体验逻辑结构如何影响SQL优化(案例3)
    查看>>
    PLSQL中INDEX BY TABLE的 DELETE操作
    查看>>
    plsql学习笔记---plsql相关概念,以及基础结构
    查看>>
    plsql数据库异常---plsql 登录后,提示数据库字符集(AL32UTF8)和客户端字符集(ZHS16GBK)不一致
    查看>>
    plsql查询乱码问题解决
    查看>>