题目描述:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=22169
/* solution: 相比与uva12661,此题是在图的结点上动了手脚。用一个n位二进制串来表示当前软件的状态,每次打完补丁后, 该状态就发生改变。所以可以把该状态看成结点,补丁打上后发生状态转移的过程看成边,就可转化成最短路问题。 但这道题不能硬套模板。需要做些变化。如note第一点。 note: 1.注意需要得到从任意结点u出发的所有边时,不是像模板里面读G[u],而是直接列举所有补丁,看看是否能够打上。 2.注意判断补丁能否打上时用的位运算表示的含义。 3.题意是关键,此题容易理解错。 4.注意输出格式。UvaOJ里面的PE(输出格式错误)有一部分是直接给的WA(错误答案)信息。不要少末尾句号。 date: 2016/4/22 add: 附上对题意的中文概括 假定有n个潜在的bug和m个补丁,每个补丁用长为n的字符串表示。首先输入bug数目以及补丁数目。然后就是对m 个补丁的描述,共有m行。每行首先是一个整数,表明打该补丁所需要的时间。然后是两个字符串,地一个字符串 是对软件的描述,只有软件处于该状态下才能打该补丁该字符串的每一个位置代表bug状态(-代表该位置没bug,+代 表该位置有bug,0表示该位置无论有没有bug都可打补丁)。然后第二个字符串是对打上补丁后软件状态的描述 -代表该位置上的bug已经被修复,+表示该位置又引入了一个新的bug, 0表示该位置跟原来状态一样)。要求用最少 时间完成对软件的修复,即将所有位置全都置为0. */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int maxBug = 20;
const int maxPatch = 105;
const int INF = 1000000000;
int n, m, t[maxPatch], d[1<<maxBug], vis[1<<maxBug];
char before[maxPatch][maxBug+5], after[maxPatch][maxBug+5];
struct Node {
int bug, dist; //dist表示到源点的距离
bool operator < (const Node& rhs) const {
return dist > rhs.dist;
}
};
int dijkstra() {
for(int i = 0; i < (1<<n); i++) { //初始化
d[i] = INF;
vis[i] = 0;
}
priority_queue<Node> q;
Node start;
start.bug = (1<<n) - 1; //n右移一位表示2的n次方。
start.dist = 0;
q.push(start);
d[start.bug] = 0;
while(!q.empty()) {
Node x = q.top(); q.pop();
if(x.bug == 0) return x.dist; //说明所有bug已经修复好,返回答案。
if(vis[x.bug]) continue;
vis[x.bug] = 1;
for(int i = 0; i < m; i++) {
bool patchable = true; //首先判断能否该补丁是否适合。
for(int j = 0; j < n; j++) {
if(before[i][j] == '-' && (x.bug & (1<<j))) {patchable = false; break;} //x.bug & (1<<j)意思是从x.bug的二进制位中取出第j位(j从0开始)
if(before[i][j] == '+' && !(x.bug & (1<<j))) {patchable = false; break;}
}
if(!patchable) continue; //若不适合就换另外补丁。
Node next; //利用所选择的补丁对其进行修复
next.bug = x.bug;
next.dist = x.dist + t[i];
for(int j = 0; j < n; j++) {
if(after[i][j] == '-') next.bug &= ~(1<<j); //将next.bug的二进制位中的第j位置为0
if(after[i][j] == '+') next.bug |= (1<<j); //将next.bug的二进制位中的第j位置为1
} //忽略为0的状况
int &D = d[next.bug]; //注意“引用”
if(next.dist < D) { //松弛操作,注意是引用,因此原变量的值也应该改变
D = next.dist;
q.push(next);
}
}
}
return -1;
}
int main()
{
//freopen("input.txt", "r", stdin);
int T = 0;
while(scanf("%d%d", &n, &m) == 2 && n) {
for(int i = 0; i < m; i++)
scanf("%d%s%s", &t[i], before[i], after[i]); //读入数据
int ans = dijkstra();
printf("Product %d\n", ++T);
if(ans < 0) printf("Bugs cannot be fixed.\n\n"); //需要注意题目要求的输出格式
else printf("Fastest sequence takes %d seconds.\n\n", ans);
}
return 0;
}