# Description
Luogu 传送门
# Solution
首先看到 ,可以想到状压,然后题目要求我们求从全部为 1 的状态到全部为 0 状态的最短时间,不难想到使用最短路或者 来解决。
对于这道题,我们使用最短路。
把每一种状态当作一个节点,每次处理一个节点时枚举所有的补丁,判断该补丁能否使用,如果可以,直接计算出使用该补丁之后的状态,即为当前点能到达的下一个点。
那么这时还有两个问题:
如何判断当前点能否使用。
把每个补丁必须有的 存到 里,必须没有的 存到 里,设当前点状态为 ,那么
(x & b1) = b1 && (x & b2) = 0
时,可以转移。如何计算使用补丁之后的状态。
同样把使用补丁之后会消失的 存到 里,会出现的 存到 里,那么由于 都会出现,所以令
x |= f2
,会消失的 如何处理呢?也很简单,先令 或上 ,再异或上 。
当然这两个都是小问题了,如果还是不理解的话看代码吧。
(另外本题每组数据后面要输出一行空行)
# Code
#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; | |
} |