题意:有N个潜在的bug和m个补丁,每个补丁用长为N的字符串表示。首先输入bug数目以及补丁数目。然后就是对M个补丁的描述,共有M行。每行首先是一个整数,表明打该补丁所需要的时间。然后是两个字符串,第一个字符串是对软件的描述,只有软件处于该状态下才能打该补丁该字符串的每一个位置代表bug状态("-"代表该位置没bug,"+"代表该位置有bug,"0"表示该位置无论有没有bug都可打补丁)。然后第二个字符串是对打上补丁后软件状态的描述"-"代表该位置上的bug已经被修复,"+"表示该位置又引入了一个新的bug, "0"表示该位置跟原来状态一样)。要求用最少时间完成对软件的修复,即将所有位置全都置为0。(N≤20)

解法:对每个bug用二进制表示,补丁两端的点通过边来转换,共2^n-1个结点。由于这样的点太多了,而实际上我们不需要这么多点。于是便像“隐式图搜索”一样,不知道所有的点,便通过所有的边来拓展。在这题中,也就是不是像平常一样用邻接表来拓展,而是枚举所有补丁,看是否能用上这条边。(注意"0"既可表示"+",也可表示"-")这样就可以从源点“11...11”开始用Dijkstra边求解边建图,直到"00...00"。

注意——由于用到了二进制的位运算,该加括号的地方千万不要漏;Dijkstra中优先队列的top()是汇点的值时就可以跳出,因为剩下的可以拓展的点都比它的值大,由于没有负权边,就不可能通过一些边又比它小了。

另外,本来我想偷懒不分析时间复杂度的,但是!!(o´・ェ・`o)我发现Dijkstra+优先队列的算法的时间是spfa的好几倍啊!于是我还是分析了一下......
Dijkstra+优先队列:由于是类“隐式图搜索”,所以每个点进行拓展的操作都是m。原先的时间复杂度是O(n log n+m),其中加的m就是每个点拓展时总共访问过一次的边。而此时这里要+km,k表示在汇点出队前入队的点树,因为每个点拓展时都遍历了一次m条所有的边啊。因此总的是O(n log n+km),最坏情况O(n log n+nm),而最坏的点是2^n。o(─.─|||
spfa:原来的时间复杂度是O(km),k为每个节点进入队列的次数,且k一般<=2。而这里尽管每个点拓展时遍历了所有边,但依旧没有使它的复杂度改变多少!!!∑(゚Д゚ノ)ノ 因为它本来主要承担这个时间复杂度的就是这个"km"啊!
总的来说就是——类“隐式图搜索”还是用spfa吧。

你们可以看看代码感受一下~ ╮(╯_╰)╭ P.S.我打得真的好粗心,所以注释有一点点儿多啊~

 1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<iostream>
5 #include<queue>
6 using namespace std;
7
8 const int N=25,NN=1<<20,M=105,INF=(int)2e9;
9 int n,m;
10 int d[NN],vis[NN];
11 struct patch{int d;char s[N],ss[N];}a[M];
12
13 struct node
14 {
15 int bug,d;
16 node() {}
17 node(int u,int v) {bug=u;d=v;}
18 bool operator < (const node& now) const
19 { return d>now.d; }//return!!!
20 };
21 priority_queue<node> q;
22
23 bool check(int x,int k)
24 {
25 for (int i=0;i<n;i++)
26 {
27 int tmp=1<<i;//反着看二进制也没什么不行的(110表示一般的011),只要没有搞错位数就好了
28 if (a[k].s[i]=='+'&& !(x&tmp)) return false;
29 if (a[k].s[i]=='-'&& (x&tmp)) return false;//()
30 }
31 return true;
32 }
33 int trans(int x,int k)
34 {
35 int full=(1<<n)-1;//()
36 for (int i=0;i<n;i++)
37 {
38 int tmp=1<<i;
39 if (a[k].ss[i]=='+') x|=tmp;
40 if (a[k].ss[i]=='-') x&=(full-tmp);//&(full-tmp) 或 & ~tmp
41 }
42 return x;
43 }
44 int solve()
45 {
46 int tmp=(1<<n)-1;//node:0~tmp
47 while (!q.empty()) q.pop();
48 for (int i=0;i<=tmp;i++) d[i]=INF,vis[i]=0;
49 node st=node(tmp,0);
50 q.push(st); d[tmp]=0;
51 while (!q.empty())
52 {
53 int x=q.top().bug;
54 if (!x) return d[0];//notice,别的再更新也是从大于它的d[x]开始更新,无更优的解了
55 q.pop();
56 if (vis[x]) continue;
57 vis[x]=1;
58 for (int i=1;i<=m;i++)
59 {
60 if (!check(x,i)) continue;
61 int y=trans(x,i);
62 if (d[x]+a[i].d<d[y])
63 {
64 d[y]=d[x]+a[i].d;
65 q.push(node(y,d[y]));
66 }
67 }
68 }
69 if (d[0]!=INF) return d[0];
70 return -1;
71 }
72 int main()
73 {
74 int T=0;
75 while (1)
76 {
77 scanf("%d%d",&n,&m);
78 if (!n && !m) break;
79 for (int i=1;i<=m;i++)
80 scanf("%d%s%s",&a[i].d,a[i].s,a[i].ss);
81 int ans=solve();
82 printf("Product %d\n",++T);
83 if (ans==-1) printf("Bugs cannot be fixed.\n");
84 else printf("Fastest sequence takes %d seconds.\n",ans);
85 printf("\n");
86 }
87 return 0;
88 }

Dijkstra+优先队列

 1 #include <cstdio>
2 #include <queue>
3 #include <cstring>
4 #include <iostream>
5 #include <cstdlib>
6 #include <algorithm>
7 #include <vector>
8 #include <map>
9 #include <string>
10 #include <set>
11 #include <ctime>
12 #include <cmath>
13 #include <cctype>
14 using namespace std;
15 #define MAX 100000
16 const int maxn = 110;
17 const int INF = 0x3f3f3f3f;
18 #define LL long long
19 int vis[(1<<20)+10];
20 int d[(1<<20)+10];
21 int s[2][maxn];
22 int t[2][maxn];
23 string s1,s2;
24 int n,m,w[maxn];
25 void dij()
26 {
27 int Max=(1<<n)-1;
28 queue<int>q;
29 for (int i = 0;i<Max;i++)
30 {
31 vis[i]=0;
32 d[i]=INF;
33 }
34 d[Max]=0;
35 q.push(Max);
36 int u,v;
37 while (!q.empty())
38 {
39 u=q.front();
40 vis[u]=0;
41 q.pop();
42 for (int i = 0;i<m;i++)
43 {
44 if ((u | s[1][i])== u && (u & (s[0][i]))==u)
45 {
46 v=u;
47 v = v | t[1][i];
48 v = v & t[0][i];
49 if (d[u]+w[i] <d[v])
50 {
51 d[v]=d[u]+w[i];
52 if (!vis[v])
53 {
54 q.push(v);
55 vis[v]=1;
56 }
57 }
58 }
59 }
60 }
61 if (d[0]==INF)
62 printf("Bugs cannot be fixed.\n");
63 else
64 printf("Fastest sequence takes %d seconds.\n",d[0]);
65 }
66 int cas=1,T;
67
68 int main()
69 {
70 while (scanf("%d%d",&n,&m)!=EOF && n)
71 {
72 memset(s,0,sizeof(s));
73 memset(t,0,sizeof(t));
74 for (int i = 0;i<m;i++)
75 {
76 cin >> w[i] >> s1 >> s2;
77 for (int j = 0;j<n;j++)
78 {
79 if (s1[j]=='+')
80 s[1][i]+=(1<<j);
81 if (s1[j]!='-')
82 s[0][i]+=(1<<j);
83 if (s2[j]=='+')
84 t[1][i]+=(1<<j);
85 if (s2[j]!='-')
86 t[0][i]+=(1<<j);
87 }
88 }
89 printf("Product %d\n",cas++);
90 dij();
91 printf("\n");
92 }
93 return 0;
94 }

spfa(来源于网上)

【uva 658】It's not a Bug, it's a Feature!(图论--Dijkstra或spfa算法+二进制表示+类“隐式图搜索”)的更多相关文章

  1. 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& ...

  2. UVA 658 It's not a Bug, it's a Feature! (最短路,经典)

    题意:有n个bug,有m个补丁,每个补丁有一定的要求(比如某个bug必须存在,某个必须不存在,某些无所谓等等),打完出来后bug还可能变多了呢.但是打补丁是需要时间的,每个补丁耗时不同,那么问题来了: ...

  3. UVA - 658 It's not a Bug, it's a Feature! (隐式图的最短路,位运算)

    隐式的图搜索,存不下边,所以只有枚举转移就行了,因为bug的存在状态可以用二进制表示,转移的时候判断合法可以用位运算优化, 二进制pre[i][0]表示可以出现的bug,那么u&pre[i][ ...

  4. UVA 658 It's not a Bug, it's a Feature!

    这个题目巧妙之处在于用二进制的每个位1,0分别表示bug的有无,以及实施补丁对相应bug的要求以及实施后的对bug的影响. 软件bug的状态:1表示相应bug仍然存在,0表示已经修复.这样可以将软件的 ...

  5. 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.对于每个补丁 ...

  6. 状态转移的最短路 隐式图搜索 UVA 658

    紫书365 题目大意:给你n个全都是bug的东西,然后每次可以修复,给你修复前后的状态,问最后如果能把bug全都修复,最少需要多少时间. 思路:从最初状态开始,然后枚举bug即可. 表示priorit ...

  7. 紫书 例题 11-6 UVa 658 (状态压缩+隐式图搜索+最短路)

    这道题用到了很多知识点, 是一道好题目.      第一用了状态压缩, 因为这里最多只有20位, 所以可以用二进制来储存状态 (要对数据范围敏感), 然后 涉及到了一些位运算.     第二这里是隐式 ...

  8. uva 10274 Fans and Gems(隐式图搜索+模拟)

    Fans and Gems Input: Standard Input Output: Standard Output Tomy's fond of a game called 'Fans and G ...

  9. uva 310 L--system(隐式图搜索+字符串处理)

     L-system  A D0L (Deterministic Lindenmayer system without interaction) system consists of a finite ...

随机推荐

  1. ASP.NET Core中的数据保护

    在这篇文章中,我将介绍ASP.NET Core 数据保护系统:它是什么,为什么我们需要它,以及它如何工作. 为什么我们需要数据保护系统? 数据保护系统是ASP.NET Core使用的一组加密api.加 ...

  2. 计算机考研真题 ZOJ问题

    题目描述 对给定的字符串(只包含'z','o','j'三种字符),判断他是否能AC. 是否AC的规则如下: 1. zoj能AC: 2. 若字符串形式为xzojx,则也能AC,其中x可以是N个'o' 或 ...

  3. 【C++】《C++ Primer 》第十三章

    第十三章 拷贝控制 定义一个类时,需要显式或隐式地指定在此类型地对象拷贝.移动.赋值和销毁时做什么. 一个类通过定义五种特殊的成员函数来控制这些操作.即拷贝构造函数(copy constructor) ...

  4. Java 用java GUI写一个贪吃蛇小游戏

    目录 主要用到 swing 包下的一些类 上代码 游戏启动类 游戏数据类 游戏面板类 代码地址 主要用到 swing 包下的一些类 JFrame 窗口类 JPanel 面板类 KeyListener ...

  5. 单片机—Arduino UNO-R3—学习笔记002

    led控制 本篇主要介绍Arduino数字引脚及相关函数,通过数字I/O输出控制板载LED灯亮灭状态(数字引脚13). 数字信号是以0.1表示的电平不连续变化的信号,也就是以二进制的形式表示的信号. ...

  6. oracle优化求生指南脚本记录

    1.查找未使用索引 /* Formatted on 2020/5/12 下午 03:32:39 (QP5 v5.163.1008.3004) */ WITH IN_PLAN_OBJECTS AS (S ...

  7. Redis-第五章节-8种数据类型

    目录 一.Redis对key的操作 二.五种数据类型 String类型 List(集合) Set(集合) Hash(哈希) Zset(有序集合) 三.三种特殊数据类型 geospatial(地理位置) ...

  8. 如何安装快速 Docker 和 Docker-Compose 服务

    最近由于个人在大家基于 Docker  的.企业级的CI/CD 环境,所以要安装 Docker 和 Docker-Compose ,这也算是一个学习过程,就把整个过程记录下来,便于以后查询. 测试环境 ...

  9. SQL 语法速成手册

    本文针对关系型数据库的一般语法.限于篇幅,本文侧重说明用法,不会展开讲解特性.原理. 一.基本概念 数据库术语 数据库(database) - 保存有组织的数据的容器(通常是一个文件或一组文件). 数 ...

  10. Linux学习安装

    Linux学习安装 服务器指的是网络中能对其他机器提供某些服务的计算机系统,相对普通PC, 服务器指的是高性能计算机,稳定性.安全性要求更高 linux安装学习 1.虚拟机 一台硬件的机器 安装vmw ...