题意:有n个bug,m个补丁,补丁要在一定条件下才能使用,使用后会发生改变。每个补丁会给出两个字符串,第一个字符串表示条件,第i位为0表示对第i个bug没有要求,+表示必须存在,-表示必须不存在;第二个字符串表示使用后的变化,-表示没有,+表示有,0表示不变。
就是最短路问题,当一个状态能使用一个补丁变化到另一个状态时就是这两个状态之间有一条边,权值就是补丁执行的时间。用二进制数表示状态,然后对于每个补丁也用二进制来处理,然后求从(1 << n) - 1开始求最短路,到0的最短距离。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
int vis[2000000];
int dis[2000000];
const int INF = 0x3f3f3f3f;
struct node{
int d, x;
node(int d, int x):d(d), x(x){}
};
bool operator <(const node &a, const node &b) {
if(a.x != b.x)
return a.x < b.x;
return a.d < b.d;
}
priority_queue<node> q;
char s[105];
int tm[101];
int st[101][4];
int main() {
int n, m, i, j, a, ks = 1;
while(~scanf("%d%d", &n, &m) && n) {
memset(vis, 0, sizeof(vis));
memset(dis, 0x3f, sizeof(dis));
for(i = 0; i < m; i++) {
scanf("%d%s", &tm[i], s);
st[i][0] = st[i][1] = 0;
for(j = 0; j < n; j++) {
st[i][0] <<= 1;
st[i][1] <<= 1;
if(s[j] == '-')
st[i][0] |= 1;
else if(s[j] == '+') st[i][1] |= 1;
}
scanf("%s", s);
st[i][2] = 0;
st[i][3] = 0;
for(j = 0; j < n; j++) {
st[i][2] <<= 1;
st[i][3] <<= 1;
if(s[j] == '+')
st[i][3] |= 1;
if(s[j] != '-')
st[i][2] |= 1;
}
}
while(q.size())
q.pop();
int u = (1 << n) - 1;
dis[u] = 0;
q.push(node(u, 0));
while(q.size()) {
node t = q.top();
q.pop();
for(i = 0; i < m; i++) {
if((t.d & st[i][0]) == 0 && (t.d & st[i][1]) == st[i][1]) {
u = (t.d & st[i][2]) | st[i][3];
if(t.x + tm[i] < dis[u]) {
dis[u] = t.x + tm[i];
q.push(node(u, dis[u]));
}
}
}
}
if(dis[0] == INF)
printf("Product %d\nBugs cannot be fixed.\n\n", ks++);
else
printf("Product %d\nFastest sequence takes %d seconds.\n\n", ks++, dis[0]);
}
return 0;
}
/**
3 3
1 000 00-
1 00- 0-+
2 0-- -++
4 1
7 0-0+ ----
0 0
**/