题意:有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. maven 无法导入ojdbc 的jar包 解决方法

    由于maven无法在线安装ojdbc包,所有先在我们需要手动导入. 准备环境: 1.系统需要配置好jdk以及maven环境. 2.ojdbc的jar包,记住jar的路径,我的路径是:E:\jdbc\o ...

  2. 【Redis3.0.x】发布订阅

    Redis3.0.x 发布订阅 基本命令 SUBSCRIBE channel [channel...] 订阅给定的一个或多个频道 PSUBSCRIBE pattern [pattern...] 订阅符 ...

  3. LeetCode142 环形链表 II

    给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 说明:不允许修改给定的链表. 进阶:你是否可以不用额外空间解决此题? //章节 - 链表 //二.双指针技巧 //2.环 ...

  4. Redis 设计与实现 10:五大数据类型之有序集合

    有序集合 sorted set (下面我们叫zset 吧) 有两种编码方式:压缩列表 ziplist 和跳表 skiplist. 编码一:ziplist zset 在 ziplist 中,成员(mem ...

  5. Python——绘制埃菲尔铁塔

    from turtle import * import turtle colormode(255) #设置turtle颜色模式 speed(0) #速度 setup(800,800,720,0) #画 ...

  6. Desired_Capabilities配置

    appium服务器初始化参数 最全: https://github.com/appium/appium/blob/master/docs/cn/writing-running-appium/caps. ...

  7. 【计算机基础】常用的快捷键和DOS命令

    常用的快捷键和DOS命令 DOS命令 使用Linux比较酷 cool

  8. 关于SSRF与CSRF漏洞的解释

    目录 SSRF服务端请求伪造(外网访问内网) 1.SSRF形成原因 2.利用SSRF漏洞的目的 3.SSRF漏洞的用途 4.SSRF漏洞的特性 实例 5.如何挖掘SSRF漏洞 6.常用SSRF去做什么 ...

  9. 史上最全postgreSQL体系结构(转)

    原文链接:https://cloud.tencent.com/developer/article/1469101 墨墨导读:本文主要从日志文件.参数文件.控制文件.数据文件.redo日志(WAL).后 ...

  10. 2020 CSP&NOIP 游记

    CSP初赛 CSP初赛 Day -1 早上打了模拟赛,T2寒假正好做过,然而还是还是被踩Orz,郑外NB!.中午出校吃了大盘鸡和拉面,还带回来了三瓶可乐. 初赛知识点看了两页不(看)想(不)看(懂)了 ...