洛谷题单指南-状态压缩动态规划-P2761 软件补丁问题

原题链接:https://www.luogu.com.cn/problem/P2761

题意解读:有n个bug,m个补丁,每个补丁运行有时间代价,每个补丁运行有特定的条件,可以修复bug引入bug,求修复所有bug所用的最小代价。

解题思路:

设所有bug的状态为(1 << n) - 1,最终要达成的状态为0,

而对于每一个状态,可以枚举运行补丁之后可以转移到哪种状态,

这样,状态之间就建立了有向图,边权即运行补丁的时间代价,

于是,问题就转化为了求从初始状态到终止状态的最短路,Dijikstra一下就好了。

注意:不用实际将图建出来,可能会爆内存,只需要从起点开始, 跑最短路就好,对于每个节点,通过计算可以得到邻接点。

100分代码:

#include <bits/stdc++.h>
using namespace std;

typedef pair<int, int> PII;
const int N = 20, M = 105;
int b1[M], b2[M], f1[M], f2[M], t[M];
int dist[1 << N], vis[1 << N];
int n, m;

void dijikstra(int start)
{
    priority_queue<PII, vector<PII>, greater<PII>> pq;
    memset(dist, 0x3f, sizeof(dist));
    dist[start] = 0;
    pq.push({dist[start], start});
    while(pq.size())
    {
        PII pii = pq.top(); pq.pop();
        int u = pii.second;
        vis[u] = true;
        for(int i = 1; i <= m; i++)
        {
            if((u & b1[i]) == b1[i] && (u & b2[i]) == 0) //包含b1,但不包含b2
            {
                int v = u & (((1 << n) - 1) ^ f1[i]); //修复所有f1
                v |= f2[i]; //引入f2
                int w = t[i];
                if(dist[v] > dist[u] + w)
                {
                    dist[v] = dist[u] + w;
                    pq.push({dist[v], v});
                }
            }
        }
    }
}

int main()
{
    cin >> n >> m;
    for(int i = 1; i <= m; i++)
    {
        string bstr, fstr;
        cin >> t[i] >> bstr >> fstr;
        for(int j = 0; j < bstr.size(); j++)
        {
            if(bstr[j] == '+') b1[i] |= (1 << j);
            if(bstr[j] == '-') b2[i] |= (1 << j);
        }
        for(int j = 0; j < fstr.size(); j++)
        {
            if(fstr[j] == '+') f2[i] |= (1 << j);
            if(fstr[j] == '-') f1[i] |= (1 << j);
        }
    }

    dijikstra((1 << n) - 1);

    if(dist[0] != 0x3f3f3f3f) cout << dist[0];
    else cout << 0;

    return 0;
}

 

posted @ 2025-08-29 15:43  hackerchef  阅读(2)  评论(0)    收藏  举报