题意:
有n个bug,m种补补丁的方式,但是补补丁可能是有条件的,比如某个位置必须有bug,或某个位置必须没有bug,且补补丁也有可能在其他地方多生成bug。
'-'表示某位置有补丁,'+'表示某位置无补丁,'0'是占位符。
输入多组数据,每组数据输入:
m n
t a1 a2 ... an b1 b2 ... bn
...
t a1 a2 ... an b1 b2 ... bn
a表示补补丁需要的条件,b表示补补丁的操作。
Sample Input:
3 3
1 000 00-
1 00- 0-+
2 0-- -++
4 1
7 0-0+ ----
0 0
Sample Output:
Product 1
Fastest sequence takes 8 seconds.
Product 2
Bugs cannot be fixed.
思路:
既然n <= 20,那么很容易想到通过状态压缩表示补丁当前的状态。那么我们需要找出从2n到0的最短路径。于是想到跑一遍最短路。这道题其实是不用建边的,我们只需要每到一个状态跑m种选择,如果符合条件就将终点(处理后的状态)入栈就好了。
附上AC代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define INF 1061109567
#define MAX (1 << 20) + 3
using namespace std;
// 大致思路:用二进制记录bug位置,每种情况为一个点,目标是从2^n走到0
// 建图不要先预处理,搜到每个点时再建边每个点判断可以到达的点
// 最后跑一遍最短路。
bool book[MAX] = {0};
int n,m,cost[150],dis[MAX];
int ch1[110][25],ch2[110][25],top1[110],top2[110];
struct node{
int order,ti;
bool operator < (const node & other)const{
return ti > other.ti;
}
};
priority_queue<node> q;
node newnode(int x,int y){
node p;
p.order = x;
p.ti = y;
return p;
}
int build(int i,int j){// i 状态 j 方案
bool fl = 1;
for(int k=0; k<= top1[j]; k++){
int r = (i >> (n - k - 1)) & 1;
if(ch1[j][k] == '+' && r == 1)continue;
if(ch1[j][k] == '-' && r == 0)continue;
if(ch1[j][k] == '0')continue;
fl = 0;
break;
}
int to = i;
if(!fl) return -1;
for(int k=0; k<= top2[j]; k++){
if(ch2[j][k] == '+')
to |= 1 << (n - k - 1);
if(ch2[j][k] == '-')//应把第n位修改为零
to &= (1 << n) - 1 - (1 << (n - k - 1));
}
if(i != to) return to;
}
void dijkstra(int o){
node p;
dis[o] = 0;
q.push(newnode(o,0));
while(!q.empty()){
p = q.top();
q.pop();
if(book[p.order])continue;
book[p.order] = 1;
for(int j=1;j<=m;j++){
int to = build(p.order,j);
if(to != -1){
if(p.ti + cost[j] < dis[to])
dis[to] = p.ti + cost[j],
q.push(newnode(to,dis[to]));
}
}
}
}
int main(){
int T = 0;
while(scanf("%d%d",&n,&m) == 2){
if(n == 0 && m == 0)break;
memset(dis,0x3f,sizeof(dis));
memset(book,0,sizeof(book));
char c;
for(int i=1; i<=m; i++){
top1[i] = -1;
scanf("%d ",&cost[i]);
c = getchar();
while(c == '0' || c == '+' || c == '-')
ch1[i][++top1[i]] = c,c = getchar();
top2[i] = -1;
c = getchar();
while(c == '0' || c == '+' || c == '-')
ch2[i][++top2[i]] = c,c = getchar();
}
dijkstra((1<<n) - 1);
if(dis[0] != INF)
printf("Product %d
Fastest sequence takes %d seconds.
",++T,dis[0]);
else printf("Product %d
Bugs cannot be fixed.
",++T);
}
return 0;
}