UVa 658 - It's not a Bug, it's a Feature!(Dijkstra + 隐式图搜索)
链接:
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个补丁,看看是否能打得上。
代码:
import java.io.*;
import java.util.*;
import static java.util.Arrays.*; public class Main {
Scanner cin = new Scanner(new BufferedInputStream(System.in));
final int INF = 0x3f3f3f3f;
final int UPN = 20;
final int UPM = 100;
int n, m, sec[] = new int[UPM], d[] = new int[1<<UPN];
char before[][] = new char[UPM][UPN], after[][] = new char[UPM][UPN];
boolean done[] = new boolean[1<<UPN]; class Node implements Comparable<Node> {
int s, dist; Node(int s, int dist) {
this.s = s;
this.dist = dist;
} @Override
public int compareTo(Node that) {
return dist - that.dist;
}
} int dijkstra() {
fill(d, INF);
fill(done, false);
int ori = (1<<n) - 1;
PriorityQueue<Node> Q = new PriorityQueue<Node>();
d[ori] = 0;
Q.add(new Node(ori, 0));
while(Q.size() > 0) {
Node cur = Q.poll();
if(cur.s == 0) return cur.dist;
if(done[cur.s]) continue;
done[cur.s] = true;
for(int t = 0; t < m; t++) {
boolean patchable = true;
for(int i = 0; i < n; i++) {
if(before[t][i] == '+' && (cur.s&(1<<i)) == 0) { patchable = false; break; }
else if(before[t][i] == '-' && (cur.s&(1<<i)) > 0) { patchable = false; break; }
}
if(!patchable) continue; Node temp = new Node(cur.s, cur.dist + sec[t]);
for(int i = 0; i < n; i++) {
if(after[t][i] == '+') temp.s |= (1<<i);
else if(after[t][i] == '-') temp.s &= ~(1<<i);
}
if(d[temp.s] > temp.dist) {
d[temp.s] = temp.dist;
Q.add(temp);
}
}
}
return -1;
} void MAIN() {
for(int cases = 1; ; cases++) {
n = cin.nextInt();
m = cin.nextInt();
if(n + m == 0) break;
for(int i = 0; i < m; i++) {
sec[i] = cin.nextInt();
before[i] = cin.next().toCharArray();
after[i] = cin.next().toCharArray();
}
int ans = dijkstra();
System.out.printf("Product %d\n", cases);
if(ans < 0) System.out.printf("Bugs cannot be fixed.\n\n");
else System.out.printf("Fastest sequence takes %d seconds.\n\n", ans);
}
} public static void main(String args[]) { new Main().MAIN(); }
}
UVa 658 - It's not a Bug, it's a Feature!(Dijkstra + 隐式图搜索)的更多相关文章
- UVA - 658 It's not a Bug, it's a Feature! (隐式图的最短路,位运算)
隐式的图搜索,存不下边,所以只有枚举转移就行了,因为bug的存在状态可以用二进制表示,转移的时候判断合法可以用位运算优化, 二进制pre[i][0]表示可以出现的bug,那么u&pre[i][ ...
- UVA 658 It's not a Bug, it's a Feature! (最短路,经典)
题意:有n个bug,有m个补丁,每个补丁有一定的要求(比如某个bug必须存在,某个必须不存在,某些无所谓等等),打完出来后bug还可能变多了呢.但是打补丁是需要时间的,每个补丁耗时不同,那么问题来了: ...
- UVA 658 It's not a Bug, it's a Feature!
这个题目巧妙之处在于用二进制的每个位1,0分别表示bug的有无,以及实施补丁对相应bug的要求以及实施后的对bug的影响. 软件bug的状态:1表示相应bug仍然存在,0表示已经修复.这样可以将软件的 ...
- UVa 658 It's not a Bug, it's a Feature! (状态压缩+Dijstra)
题意:首先给出n和m,表示有n个bug和m个补丁.一开始存在n个bug,用1表示一个bug存在0表示不存在,所以一开始就是n个1,我们的目的是要消除所有的bug, 所以目标状态就是n个0.对于每个补丁 ...
- 【UVA】658 - It's not a Bug, it's a Feature!(隐式图 + 位运算)
这题直接隐式图 + 位运算暴力搜出来的,2.5s险过,不是正法,做完这题做的最大收获就是学会了一些位运算的处理方式. 1.将s中二进制第k位变成0的处理方式: s = s & (~(1 < ...
- 【uva 658】It's not a Bug, it's a Feature!(图论--Dijkstra或spfa算法+二进制表示+类“隐式图搜索”)
题意:有N个潜在的bug和m个补丁,每个补丁用长为N的字符串表示.首先输入bug数目以及补丁数目.然后就是对M个补丁的描述,共有M行.每行首先是一个整数,表明打该补丁所需要的时间.然后是两个字符串,第 ...
- 状态转移的最短路 隐式图搜索 UVA 658
紫书365 题目大意:给你n个全都是bug的东西,然后每次可以修复,给你修复前后的状态,问最后如果能把bug全都修复,最少需要多少时间. 思路:从最初状态开始,然后枚举bug即可. 表示priorit ...
- 紫书 例题 11-6 UVa 658 (状态压缩+隐式图搜索+最短路)
这道题用到了很多知识点, 是一道好题目. 第一用了状态压缩, 因为这里最多只有20位, 所以可以用二进制来储存状态 (要对数据范围敏感), 然后 涉及到了一些位运算. 第二这里是隐式 ...
- uva 10274 Fans and Gems(隐式图搜索+模拟)
Fans and Gems Input: Standard Input Output: Standard Output Tomy's fond of a game called 'Fans and G ...
随机推荐
- jQuery 自定义方法(扩展方法)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- c++ mysql connector 学习汇总
1)MySQL Connector/C++入门教程(上) 里面有autoCommit的用法 2)国外的一篇文章
- C# 处理XML的基本操作
文章部分代码引用参考文章, 文末参考文章已标注 ,本篇文章建立在两篇参考文章基础上,可以先阅读参考文章 XML 相关类 XDocument XmlDocument XmlReader XmlWrit ...
- Java中的断言 Assert
今天正好遇到了,就记一下 一.作用: 用与编写单元测试 二.assert 关键字 assert 理论上和 if类似, 但是assert 仅仅用于测试, 不能用于业务 如果发现断言无效, 则可能时ide ...
- 初步理解require.js模块化编程
初步理解require.js模块化编程 一.Javascript模块化编程 目前,通行的Javascript模块规范共有两种:CommonJS和AMD. 1.commonjs 2009年,美国程序员R ...
- java.sql.SQLException: Incorrect string value: '\xF0\x9F\x9A\x80\xF0\x9F...' for column 'name' at row 1
1.异常提示: 12:59:10.000 [http-nio-8080-exec-40] DEBUG o.s.j.s.SQLStateSQLExceptionTranslator - Extracte ...
- JavaScript练习笔记整理·4 - 6.26
基础练习(1): 我的解答为: function getMiddle(s) { if(s.length%2 == 0) { return s.charAt(s.length/2-1)+s.charAt ...
- Angular1组件通讯方式总结
这里需要将Angular1分为Angular1.5之前和Angular1.5两个不同的阶段来讲,两者虽然同属Angular1,但是在开发模式上还是有较大区别的.在Angular1.4及以前,主要是基于 ...
- iOS线程和进程的区别和联系
线程和进程的区别主要在于它们是不同的操作系统资源管理方式.进程有独立的地址空间,一个进程崩溃后,在保护模式的影响下不会对其他进程产生影响,而线程只是一个进程中的不同执行路径.线程有自己的堆栈和局部变量 ...
- CentOS 7运维管理笔记(10)----MySQL源码安装
MySQL可以支持多种平台,如Windows,UNIX,FreeBSD或其他Linux系统.本篇随笔记录在CentOS 7 上使用源码安装MySQL的过程. 1.下载源码 选择使用北理工的镜像文件: ...