【uva 658】It's not a Bug, it's a Feature!(图论--Dijkstra或spfa算法+二进制表示+类“隐式图搜索”)
题意:有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算法+二进制表示+类“隐式图搜索”)的更多相关文章
- 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& ...
- 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! (隐式图的最短路,位运算)
隐式的图搜索,存不下边,所以只有枚举转移就行了,因为bug的存在状态可以用二进制表示,转移的时候判断合法可以用位运算优化, 二进制pre[i][0]表示可以出现的bug,那么u&pre[i][ ...
- 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
紫书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 ...
- uva 310 L--system(隐式图搜索+字符串处理)
L-system A D0L (Deterministic Lindenmayer system without interaction) system consists of a finite ...
随机推荐
- 深入理解Go Context
目录 emptyCtx类型 cancelCtx类型 timerCtx类型 valueCtx类型 在Go语言并发编程中,用一个goroutine来处理一个任务,而它又会创建多个goroutine来负责不 ...
- C#处理医学图像(二):基于Hessian矩阵的医学图像增强与窗宽窗位
根据本系列教程文章上一篇说到,在完成C++和Opencv对Hessian矩阵滤波算法的实现和封装后, 再由C#调用C++ 的DLL,(参考:C#处理医学图像(一):基于Hessian矩阵的血管肺纹理骨 ...
- Flutter 基础组件:进度指示器
前言 Material 组件库中提供了两种进度指示器:LinearProgressIndicator和CircularProgressIndicator,它们都可以同时用于精确的进度指示和模糊的进度指 ...
- Head First 设计模式 —— 13. 代理 (Proxy) 模式
思考题 如何设计一个支持远程方法调用的系统?你要怎样才能让开发人员不用写太多代码?让远程调用看起来像本地调用一样,毫无瑕疵? P435 已经接触过 RPC 了,所以就很容易知道具体流程:客户端调用目标 ...
- JavaScript入门-对象
js对象 本篇主要介绍js里如何创建对象,以及for循环访问对象的成员... 什么是对象? 对象,并不是中文里有男女朋友意思,它是从英文里翻译来的,英文叫[Object],目标,物体,物品的意思. 在 ...
- 【EXP】导出数据库dmp文件,只有几张表有数据,剩下的所有表只有表结构没有数据
导出一个dmp,指定的表中有数据,其他的表只有表结构, 有数据的表只有几张,分别是A,B,C三张表,剩下的表都没有数据 思路: 导出一个111.dmp,所有的表都只是表结构 将111.dmp导入到新创 ...
- dmp文件导入抽取方法
一.确认dmp文件.oracle客户端和服务端的字符集 (1)dmp文件字符集确认: 使用UE打开dmp文件查看文件第2个和第3个字节内容,这两个字节记录了dmp文件的字符集.如0354,然后用以下s ...
- os-Bytes环境变量劫持
信息收集 netdiscovery -i eth0 nmap -sV -sC 192.168.43.74 -oA os-Bytes gobuster -u 192.168.43.74 -w /usr/ ...
- ORACLE查找占用临时表空间多的SESSION
需要使用SYS用户登录查看 /* Formatted on 2020/12/30 上午 11:17:12 (QP5 v5.163.1008.3004) */ SELECT k.inst_id &quo ...
- oracle视图添加hint
/* Formatted on 2019/8/6 下午 02:51:21 (QP5 v5.163.1008.3004) */ SELECT DB FROM ( SELECT /*+ index(A.r ...