洛谷题单指南-状态压缩动态规划-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;
}