链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=599
题意:
补丁在修正bug时,有时也会引入新的bug。假定有n(n≤20)个潜在bug和m(m≤100)个补丁,
每个补丁用两个长度为n的字符串表示,其中字符串的每个位置表示一个bug。
第一个串表示打补丁之前的状态(“-”表示该bug必须不存在,“+”表示必须存在,0表示无所谓),
第二个串表示打补丁之后的状态(“-”表示不存在,“+”表示存在,0表示不变)。
每个补丁都有一个执行时间,你的任务是用最少的时间把一个所有bug都存在的软件通过打补丁的方式变得没有bug。
一个补丁可以打多次。
分析:
在任意时刻,每个bug可能存在也可能不存在,所以可以用一个n位二进制串表示当前软件的“状态”。
打完补丁之后,bug状态会发生改变,对应“状态转移”。
把状态看成结点,状态转移看成边,转化成图论中的最短路径问题,然后使用Dijkstra算法求解。
不过这道题和普通的最短路径问题不一样:结点很多,多达2^n个,
而且很多状态根本遇不到(即不管怎么打补丁,也不可能打成那个状态),所以没有必要先把图储存好。
用隐式图搜索即可:当需要得到某个结点u出发的所有边时,直接枚举所有m个补丁,看看是否能打得上。
代码:
1 import java.io.*; 2 import java.util.*; 3 import static java.util.Arrays.*; 4 5 public class Main { 6 Scanner cin = new Scanner(new BufferedInputStream(System.in)); 7 final int INF = 0x3f3f3f3f; 8 final int UPN = 20; 9 final int UPM = 100; 10 int n, m, sec[] = new int[UPM], d[] = new int[1<<UPN]; 11 char before[][] = new char[UPM][UPN], after[][] = new char[UPM][UPN]; 12 boolean done[] = new boolean[1<<UPN]; 13 14 class Node implements Comparable<Node> { 15 int s, dist; 16 17 Node(int s, int dist) { 18 this.s = s; 19 this.dist = dist; 20 } 21 22 @Override 23 public int compareTo(Node that) { 24 return dist - that.dist; 25 } 26 } 27 28 int dijkstra() { 29 fill(d, INF); 30 fill(done, false); 31 int ori = (1<<n) - 1; 32 PriorityQueue<Node> Q = new PriorityQueue<Node>(); 33 d[ori] = 0; 34 Q.add(new Node(ori, 0)); 35 while(Q.size() > 0) { 36 Node cur = Q.poll(); 37 if(cur.s == 0) return cur.dist; 38 if(done[cur.s]) continue; 39 done[cur.s] = true; 40 for(int t = 0; t < m; t++) { 41 boolean patchable = true; 42 for(int i = 0; i < n; i++) { 43 if(before[t][i] == '+' && (cur.s&(1<<i)) == 0) { patchable = false; break; } 44 else if(before[t][i] == '-' && (cur.s&(1<<i)) > 0) { patchable = false; break; } 45 } 46 if(!patchable) continue; 47 48 Node temp = new Node(cur.s, cur.dist + sec[t]); 49 for(int i = 0; i < n; i++) { 50 if(after[t][i] == '+') temp.s |= (1<<i); 51 else if(after[t][i] == '-') temp.s &= ~(1<<i); 52 } 53 if(d[temp.s] > temp.dist) { 54 d[temp.s] = temp.dist; 55 Q.add(temp); 56 } 57 } 58 } 59 return -1; 60 } 61 62 void MAIN() { 63 for(int cases = 1; ; cases++) { 64 n = cin.nextInt(); 65 m = cin.nextInt(); 66 if(n + m == 0) break; 67 for(int i = 0; i < m; i++) { 68 sec[i] = cin.nextInt(); 69 before[i] = cin.next().toCharArray(); 70 after[i] = cin.next().toCharArray(); 71 } 72 int ans = dijkstra(); 73 System.out.printf("Product %d ", cases); 74 if(ans < 0) System.out.printf("Bugs cannot be fixed. "); 75 else System.out.printf("Fastest sequence takes %d seconds. ", ans); 76 } 77 } 78 79 public static void main(String args[]) { new Main().MAIN(); } 80 }