UVA 658 It's not a Bug, it's a Feature! (最短路,经典)
题意:有n个bug,有m个补丁,每个补丁有一定的要求(比如某个bug必须存在,某个必须不存在,某些无所谓等等),打完出来后bug还可能变多了呢。但是打补丁是需要时间的,每个补丁耗时不同,那么问题来了:要打多久才能无bug?(同1补丁可重复打)
分析:
n<=20,那么用位来表示bug的话有220=100万多一点。不用建图了,图实在太大了,用位图又不好玩。那么直接用隐式图搜索(在任意点,只要满足转移条件,任何状态都能转)。
但是有没有可能每个状态都要搜1次啊?那可能是100万*100万啊,这样出题还有解么?大部分状态是怎么打补丁都到不了的,但是具体要说是多少个也不能这么说吧,这个分析可能也太麻烦了,设计100个补丁能将n个1打成所有状态都覆盖就差不多超时了。(出题人应该不会这么精明,忽略这个问题)
那么用位表示状态要怎么办?类似于状态压缩的感觉,每个bug有3种可能(必存在,必不存在,无所谓),只要40个位搞定,但是两个位表示1个bug状态也太麻烦了吧?那就开两个数组咯,配合表示就行了,丝毫没有省空间!!但是容易看了。但是这么设计使得在匹配的时候神速啊。
思路:
一开始所有bug是存在的,所以有sta=末尾n个1。接着我们要将其打成sta=0,任务艰巨,赶紧开始。
(1)首先求状态的上限up。将1左移n个位置再减少1。
(2)dijkstra来穷举每个状态,即0~up。用优先队列来优化它,一旦距离dist有更新,就进队(这么像SPFA!其实用了优先队列,一点不像,只要vis[该点]=1,那就忽略它,而spfa不忽略)。
(3)当队列不空一直循环,直到循环了up次,或者可达状态全部遍历过了,就退出了,直接检查dist[0]是否为无穷大。
难点:
其实这题考的不是SSSP,而是位运算的设计。
(1)如何检查m个bug种哪些是可以转移的?
数组pat_r1[i]表示第i个补丁需要哪些bug必须存在,存在则该位为1;
数组pat_r2[i]表示第i个补丁对那些bug无所谓,无所谓的位为0。
假设本状态为flag,判断第j个补丁是否可以打,应该这样:
int res=(flag^pat_r1[j]); //异或完,满足要求的(即相同的)位会为0(无所谓的先不管)。
res&=pat_r2[j]; //将无所谓的位全部置为0。
if(res==0) return true; //满足要求
(2)如何获取转移后的状态?
数组pat_o1[i]表示第i个补丁打完后输出的哪些bug依然存在,存在则该位为1;
数组pat_o2[i]表示第i个补丁打完后输出的哪些bug依然不变,不会变的位为1。
假设本状态为flag,打完补丁j 输出的结果应该是:
int tmp=(flag&pat_o2[j]); //将不变的取出来
tmp+=pat_o1[j]; //将不变的补回去
return tmp; //打完了
#include <bits/stdc++.h>
#define LL long long
#define pii pair<int,int>
using namespace std;
const int N=+;
const int INF=0x7f7f7f7f;
int pat_r1[N]; //补丁所需要的要求1
int pat_r2[N]; //补丁所需要的要求2,记录无所谓
int val[N]; //权值
int pat_o1[N]; //打完补丁后的产出1
int pat_o2[N]; //打完补丁后的产出2,记录不变
int dist[]; //表示状态
bool vis[];
int bugs, patches, v;
int res, tmp; //临时变量 /*
int cal() //超时!!未优化的dijkstra。
{
memset(dist,0x7f,sizeof(dist));
memset(vis,0,sizeof(vis)); int t=bugs, up=1;
while(t--) up+=up;
dist[--up]=0;
for(int i=up; i>=0; i--)
{
int small=INF, flag=INF;
for(int j=0; j<=up; j++) //在状态j中找dist最短
{
if(!vis[j]&&dist[j]<small)
{
flag=j; //标记该状态
small=dist[j]; //snall保存所耗时间
}
}
if(flag==INF) return -1; //找不到 vis[flag]=1; for(int j=1; j<=patches; j++) //扫描每个补丁
{
//检查是否满足条件
res=(flag^pat_r1[j]); //异或完,满足要求的会为0(除了无所谓的)。
res&=pat_r2[j]; //将无所谓的位全部置为0。 if( !res ) //只要为0就是满足条件
{
tmp=(flag&pat_o2[j]); //将不变的取出来
tmp+=pat_o1[j]; //将不变的补回去
if( dist[tmp]>dist[flag]+val[j] ) //时间比较短的
{
dist[tmp]=dist[flag]+val[j];
if(!tmp) return dist[tmp]; //bug全部修复
}
}
}
}
return -1; //修不了 } */ int can_use(int flag, int j)
{
//检查是否满足条件
int res=(flag^pat_r1[j]); //异或完,满足要求的会为0(除了无所谓的)。
res&=pat_r2[j]; //将无所谓的位全部置为0。
if(res==) return true;
return false;
} int get_sta(int flag, int j)
{
//获取将要更新的状态
int tmp=(flag&pat_o2[j]); //将不变的取出来
tmp+=pat_o1[j]; //将不变的补回去
return tmp;
} int cal()
{
priority_queue<pii, vector<pii>, greater<pii> > que; memset(vis, , sizeof(vis));
memset(dist, 0x7f, sizeof(dist)); int t=bugs, up=;
while(t--) up+=up; //获取上限
dist[--up]=; que.push(make_pair(,up));
while(!que.empty())
{
int flag=que.top().second; que.pop();
if(vis[flag]) continue; //重复
vis[flag]=; for(int j=; j<=patches; j++) //扫描每个补丁
{
int tmp=get_sta(flag, j);
if( can_use(flag, j) && dist[tmp]>dist[flag]+ val[j] ) //只要为0就是满足条件
{
dist[tmp]=dist[flag]+ val[j];
que.push(make_pair(dist[tmp],tmp));
}
}
}
return dist[];
} int main()
{
freopen("input.txt", "r", stdin);
char s[], s2[];
int Case=;
while(scanf("%d %d", &bugs, &patches ), bugs||patches)
{
for(int i=; i<=patches; i++)
{
scanf("%d %s %s", &v, s, s2);
val[i]=v;
pat_r1[i]= pat_r2[i]= ;
for(int j=; j<=bugs; j++) //要求
{
pat_r1[i]<<=;
pat_r2[i]<<=; if(s[j-]=='+') //'+'用1表示,'-'用0表示(直接移位,不用处理)
pat_r1[i]++;
if(s[j-]!='') //无所谓用0表示
pat_r2[i]++;
} pat_o1[i]= pat_o2[i]= ;
for(int j=; j<=bugs; j++) //输出
{
pat_o1[i]<<=;
pat_o2[i]<<=;
if(s2[j-]=='+') //有bug就1,无bug为0
pat_o1[i]++;
if(s2[j-]=='') //不变为1
pat_o2[i]++;
}
}
printf("Product %d\n",++Case);
int ans=cal();
if(ans<INF) printf("Fastest sequence takes %d seconds.\n\n", ans );
else printf("Bugs cannot be fixed.\n\n");
}
return ;
}
AC代码177ms
#include <bits/stdc++.h>
#define LL long long
#define pii pair<int,int>
using namespace std;
const int N=+;
const int INF=0x7f7f7f7f;
int pat_r1[N], pat_r2[N], pat_o1[N], pat_o2[N], val[N], dist[], vis[];
int bugs, patches, v; int can_use(int flag, int j)
{
int res=(flag^pat_r1[j]); //异或完,满足要求的会为0(除了无所谓的)。
res&=pat_r2[j]; //将无所谓的位全部置为0。
if(res==) return true;
return false;
} int get_sta(int flag, int j)
{
int tmp=(flag&pat_o2[j]); //将不变的取出来
tmp+=pat_o1[j]; //将不变的补回去
return tmp;
} int cal()
{
priority_queue<pii, vector<pii>, greater<pii> > que;
memset(vis, , sizeof(vis));
memset(dist, 0x7f, sizeof(dist));
int up=;
while(bugs--) up+=up;
dist[--up]=; que.push(make_pair(,up));
while(!que.empty())
{
int flag=que.top().second; que.pop();
vis[flag]=;
for(int j=; j<=patches; j++) //扫描每个补丁
{
int tmp=get_sta(flag, j);
if( can_use(flag, j) && dist[tmp]>dist[flag]+ val[j] ) //只要为0就是满足条件
{
dist[tmp]=dist[flag]+ val[j];
if(!vis[tmp]) que.push(make_pair(dist[tmp],tmp));
//if(!tmp) return dist[0]; //不能这么做,可能还有更新,这只是更新第一次而已,至少要n次
}
}
}
return dist[];
} int main()
{
freopen("input.txt", "r", stdin);
char s[], s2[];
int Case=;
while(scanf("%d %d", &bugs, &patches ), bugs||patches)
{
for(int i=; i<=patches; i++)
{
scanf("%d %s %s", &v, s, s2);
val[i]=v;
pat_r1[i]= pat_r2[i]= pat_o1[i]= pat_o2[i]= ;
for(int j=; j<=bugs; j++)
{
pat_r1[i]<<=,pat_r2[i]<<=,pat_o1[i]<<=,pat_o2[i]<<=;
if(s[j-]=='+') pat_r1[i]++;
if(s[j-]!='') pat_r2[i]++;
if(s2[j-]=='+') pat_o1[i]++;
if(s2[j-]=='') pat_o2[i]++;
}
}
int ans=cal();
if(ans<INF) printf("Product %d\nFastest sequence takes %d seconds.\n\n",++Case, ans );
else printf("Product %d\nBugs cannot be fixed.\n\n",++Case);
}
return ;
}
短码AC版本
UVA 658 It's not a Bug, it's a Feature! (最短路,经典)的更多相关文章
- 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!
这个题目巧妙之处在于用二进制的每个位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! (隐式图的最短路,位运算)
隐式的图搜索,存不下边,所以只有枚举转移就行了,因为bug的存在状态可以用二进制表示,转移的时候判断合法可以用位运算优化, 二进制pre[i][0]表示可以出现的bug,那么u&pre[i][ ...
- [有意思]The IT workers of Star Wars -- That's not a bug. It's a feature
Yeah, that Artoo is kinda mouthy... ... now select, "restore to factory settings." That'll ...
- poj1483 It's not a Bug, It's a Feature!
It's not a Bug, It's a Feature! Time Limit: 5000MS Memory Limit: 30000K Total Submissions: 1231 ...
- 【最短路】【位运算】It's not a Bug, it's a Feature!
[Uva658] It's not a Bug, it's a Feature! 题目略 UVA658 Problem PDF上有 试题分析: 本题可以看到:有<=20个潜在的BUG,那 ...
- uva_658_It's not a Bug, it's a Feature!(最短路)
It's not a Bug, it's a Feature! Time Limit: 3000MS Memory Limit: Unknown 64bit IO Format: %lld & ...
- UVa 658 (Dijkstra) It's not a Bug, it's a Feature!
题意: 有n个BUG和m个补丁,每个补丁用一个串表示打补丁前的状态要满足的要求,第二个串表示打完后对补丁的影响,还有打补丁所需要的时间. 求修复所有BUG的最短时间. 分析: 可以用n个二进制位表示这 ...
随机推荐
- 查看系统网络连接打开端口、系统进程、DOS打开文件
问题描述: DOS查看系统网络连接打开端口.打开的服务 问题解决: (1)DOS查看系统网络连接打开端口 注: 使用 netstat 命令,可以查看系统打开的端口 (2)查看和关闭系统打开进程 ...
- jquery-validation 学习总结
一.用前必备 项目主页:http://bassistance.de/jquery-plugins/jquery-plugin-validation/ API: http://jquery.bassis ...
- JS内存管理测试
打开调试器,切换到timer,点击左下角的record按钮开始,切换到memory视图,在文档中点击鼠标左右键,看股价走势图 function Allocate(kbs){ this.mem = ne ...
- Unity3D脚本中文系列教程(十三)
http://dong2008hong.blog.163.com/blog/static/469688272014032334486/ Unity3D脚本中文系列教程(十二) ◆ function G ...
- POJ 1258 Agri-Net(最小生成树,基础)
题目 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #include<math ...
- C++ Variables and Basic Types Notes
1. Type conversion: If we assign an out-of-range value to an object of unsigned type, the result is ...
- Ubuntu环境下手动配置HBase0.94.25
/×××××××××××××××××××××××××××××××××××××××××/ Author:xxx0624 HomePage:http://www.cnblogs.com/xxx0624/ ...
- lintcode:previous permutation上一个排列
题目 上一个排列 给定一个整数数组来表示排列,找出其上一个排列. 样例 给出排列[1,3,2,3],其上一个排列是[1,2,3,3] 给出排列[1,2,3,4],其上一个排列是[4,3,2,1] 注意 ...
- Nim语言:Pascal的语法,Python的缩进
http://nim-lang.org/ 德国人Andreas Rumpf的作品,原因是他对过去使用的每种语言都不满意(Pascal也不满意?).以前叫Nimrod语言,从0.96版本开始改名为Nim ...
- 在PowerDesigner中设计物理模型1——表和主外键
原文:在PowerDesigner中设计物理模型1--表和主外键 在PD中建立物理模型由以下几种办法: 直接新建物理模型. 设计好概念模型,然后由概念模型生成物理模型. 设计好逻辑模型,然后由逻辑模型 ...