题意:
某个软件有n个漏洞m的补丁,而每个补丁修复漏洞有前提条件,即有些漏洞必须存在或不存在,每个补丁的修复时间各不相同,现在有n个漏洞,让你求出把这n个漏洞全部修复所花的最少时间。
解析:
这个题目可以转化为最短路的模型来求解。由n个1或0来表示bug,我们很容易联想要二进制和十进制的转化,对于当前的bug状态,我们可以转化为1个十进制来表示,那么一开始的状态显然就是2^n-1,目标状态就是0,也就是从2^n-1转化为0,用时最少,相当于从2^n-1到0的最短路
对于一个补丁,其实就是一些有向边(是有向边,而且不是一条,可能是多条,所以是一些),为什么?因为对于当前的bug状态我们转化为十进制u,扫描所有的补丁,找到可以使用的补丁,并在这个补丁作用下变为一个新的bug状态,这个新的bug状态也对应一个十进制v,所以其实就是u到v,有向边u–>v,边权就是使用补丁使用的时间。
一种思路是先建图,再来一个最短路,但是会超时,因为图的顶点太多,边也很多。n的上限是20,即顶点个数为2^20-1,而边数在最坏情况下很大的,一定会超时。而我们思考可以知道,很多顶点是不一定会经过的,也就是很多bug的状态不会出现,所以我们为什么不一边最短路一边建图呢?所以我们可以就用dijkstra+优先队列的做法来求解。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 105;
const int MAXN = (1<<21) + 10;
int n, m;
struct Oper {
char from[25], to[25];
int val;
}op[N];
struct Node {
int u, dist;
friend bool operator < (Node a, Node b) {
return a.dist > b.dist;
}
};
bool vis[MAXN];
int d[MAXN];
priority_queue<Node> que;
void init() {
memset(vis, false, sizeof(vis));
memset(d, INF, sizeof(d));
while(!que.empty()) que.pop();
}
bool judge(int state, Oper oper) {
for(int i = n-1, j = 0; i >= 0; i--, j++) {
if(oper.from[i] == '-') {
if((state >> j & 1) != 0)
return false;
}else if(oper.from[i] == '+') {
if((state >> j & 1) != 1)
return false;
}
}
return true;
}
int trans(int state, Oper oper) {
int full = (1<<n)-1;
for(int i = n-1, j = 0; i >= 0; i--, j++) {
if(oper.to[i] == '+') {
state |= (1 << j);
}else if(oper.to[i] == '-') {
state &= (full-(1 << j));
}
}
return state;
}
int spfa(int start) {
d[start] = 0;
que.push((Node){start, d[start]});
while(!que.empty()) {
Node node = que.top();
que.pop();
int u = node.u;
if(vis[u]) continue;
vis[u] = true;
for(int i = 0; i < m; i++) {
if(judge(u, op[i])) {
int v = trans(u, op[i]);
if(d[v] > d[u] + op[i].val) {
d[v] = d[u] + op[i].val;
que.push((Node){v, d[v]});
}
}
}
}
return d[0];
}
int main() {
int cas = 1;
while(scanf("%d%d", &n, &m) != EOF && (n || m)) {
init();
for(int i = 0; i < m; i++) {
scanf("%d%s%s", &op[i].val, op[i].from, op[i].to);
}
int ans = spfa((1<<n)-1);
printf("Product %d\n", cas++);
if(ans == INF) {
puts("Bugs cannot be fixed.");
}else {
printf("Fastest sequence takes %d seconds.\n", ans);
}
puts("");
}
return 0;
}
本文介绍了一种利用最短路径算法解决软件漏洞修复顺序的问题。通过将漏洞状态转化为二进制表示,采用 Dijkstra 算法结合优先队列进行高效计算,以找出修复所有漏洞所需的最短时间。
1077

被折叠的 条评论
为什么被折叠?



