# Description

Luogu传送门

# Solution

首先看到 n20n \leq 20,可以想到状压,然后题目要求我们求从全部为 1 的状态到全部为 0 状态的最短时间,不难想到使用最短路或者 dp\text{dp} 来解决。

对于这道题,我们使用最短路。

把每一种状态当作一个节点,每次处理一个节点时枚举所有的补丁,判断该补丁能否使用,如果可以,直接计算出使用该补丁之后的状态,即为当前点能到达的下一个点。

那么这时还有两个问题:

  • 如何判断当前点能否使用。

    把每个补丁必须有的 bug\text{bug} 存到 b1b_1 里,必须没有的 bug\text{bug} 存到 b2b_2 里,设当前点状态为 xx,那么 (x & b1) = b1 && (x & b2) = 0 时,可以转移。

  • 如何计算使用补丁之后的状态。

    同样把使用补丁之后会消失的 bug\text{bug} 存到 f1f_1 里,会出现的 bug\text{bug} 存到 f2f_2 里,那么由于 f2f_2 都会出现,所以令 x |= f2,会消失的 bug\text{bug} 如何处理呢?也很简单,先令 xx 或上 f1f_1,再异或上 f1f_1

当然这两个都是小问题了,如果还是不理解的话看代码吧。

(另外本题每组数据后面要输出一行空行)

# Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <bits/stdc++.h>

using namespace std;

namespace IO{
inline int read(){
int x = 0;
char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}

template <typename T> inline void write(T x){
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
}
using namespace IO;

const int N = 110;
const int inf = 1e9;
int n, m, sta;
struct node{
int t, b1, b2, f1, f2;
}p[N];
char s[N];
int dis[(1 << 21) + 5];
bool vis[(1 << 21) + 5];

inline void spfa(){
memset(dis, 0x3f, sizeof(dis));
queue <int> q;
q.push(sta = (1 << n) - 1), dis[sta] = 0;
while(!q.empty()){
int x = q.front(); q.pop();
vis[x] = 0;
for(int i = 1; i <= m; ++i)
if((x & p[i].b1) == p[i].b1 && !(x & p[i].b2)){
int y = (x | p[i].f1 | p[i].f2) ^ p[i].f1;
if(dis[y] > dis[x] + p[i].t){
dis[y] = dis[x] + p[i].t;
if(!vis[y]) vis[y] = 1, q.push(y);
}
}
}
}

inline void Clear(){
for(int i = 1; i <= m; ++i) p[i] = (node){0, 0, 0, 0, 0};
}

signed main(){
int Case = 0;
while(scanf("%d%d", &n, &m) && n && m){
for(int i = 1; i <= m; ++i){
p[i].t = read();
scanf("%s", s);
for(int j = 0; j < n; ++j){
if(s[j] == '+') p[i].b1 |= (1 << j);
if(s[j] == '-') p[i].b2 |= (1 << j);
}
scanf("%s", s);
for(int j = 0; j < n; ++j){
if(s[j] == '-') p[i].f1 |= (1 << j);
if(s[j] == '+') p[i].f2 |= (1 << j);
}
}
spfa(), Clear();
printf("Product %d\n", ++Case);
if(dis[0] >= inf) printf("Bugs cannot be fixed.\n\n");
else printf("Fastest sequence takes %d seconds.\n\n", dis[0]);
}
return 0;
}