# 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; | |
| } | 
