[CTSC1999][网络流24题]补丁VS错误
发布日期:2025-04-06 05:59:18 浏览次数:14 分类:精选文章

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

#洛谷P2761、vijos P1019、codevs1239、codevs2218#

题目大意

有n个错误,m个不同的补丁。每个补丁都有两个描述字符串:“+”和“-”。使用一个补丁的条件是当前的错误集合必须包含“+”字符串中所有的错误,但不包含“-”字符串中的任何错误。使用该补丁后,会修复“-”字符串中的所有错误,同时新增“+”字符串中的错误。每个补丁使用一次需要一定的时间,问最短需要多少时间才能修复所有错误。如果无法完成,输出0。

解题思路

  • 状态表示:使用20位整数来表示n个错误,每一位代表一个错误状态。例如,第j位为1表示错误j存在,0表示修复。

  • 状态转移:从一个状态u使用补丁i,可以得到状态to。判断条件是:

    • u包含补丁i的“+”字符串中的所有错误。
    • u不包含补丁i的“-”字符串中的任何错误。
    • 使用补丁i后,修复“-”字符串中的错误,并新增“+”字符串中的错误。
  • 最短路径算法:使用Dijkstra算法,找出从初始状态(全1)到目标状态(0)的最短路径。每个状态的距离记录最短时间。

  • 优化技巧:使用优先队列处理状态,按时间优先处理。状态转移时,通过位运算高效判断。

  • 代码实现

    #include 
    #include
    #include
    int n, m;
    int dis[1 << 21];
    bool vis[1 << 21];
    struct Buding {
    int t;
    int has, donthas, ac, wa;
    Buding(int t = 0) : has(0), donthas(0), ac(0), wa(0) {}
    Buding(int t, int h, int d, int a, int w) : has(h), donthas(d), ac(a), wa(w), t(t) {}
    };
    Buding e[m + 1];
    char b[30], f[30];
    std::queue
    q;
    int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= m; ++i) {
    scanf("%d %s %s", &e[i].t, b, f);
    e[i].has = 0;
    e[i].donthas = 0;
    for (int j = 0; j < n; ++j) {
    if (b[j] == '-') e[i].donthas |= 1 << j;
    if (f[j] == '-') e[i].ac |= 1 << j;
    }
    }
    int initial = (1 << n) - 1;
    dis[initial] = 0;
    vis[initial] = true;
    q.push(initial);
    while (!q.empty()) {
    int u = q.front();
    q.pop();
    if (dis[u] != dis[u]) continue;
    for (int i = 1; i <= m; ++i) {
    Buding &p = e[i];
    if ((u & p.has) == p.has && (u & p.donthas) == 0) {
    int to = (p.wa | (~p.ac)) | p.has;
    if (dis[u] + p.t < dis[to]) {
    dis[to] = dis[u] + p.t;
    if (!vis[to]) {
    vis[to] = true;
    q.push(to);
    }
    }
    }
    }
    }
    if (dis[0] == 0x3f3f3f3f) puts("0");
    else puts(dis[0]);
    return 0;
    }

    代码解释

  • 结构体定义Buding结构体存储补丁的相关信息,包括时间、错误掩码等。

  • 输入处理:读取n和m,初始化补丁数组,读取每个补丁的参数,并根据描述字符串生成掩码。

  • 初始化:将初始状态加入优先队列,距离设为0。

  • Dijkstra算法:处理队列中的每个状态,遍历所有补丁,判断是否可以使用,计算新状态并更新距离。

  • 结果输出:检查目标状态的距离,如果为无穷大,输出0,否则输出最短时间。

  • 上一篇:linux sort 用法
    下一篇:Linux Socket学习--域和套接口简介

    发表评论

    最新留言

    初次前来,多多关照!
    [***.217.46.12]2025年05月12日 16时03分21秒