洛谷 题解 UVA658 【这不是bug,而是特性 It's not a Bug, it's a Feature!】
【题意】
补丁在修正\(BUG\)时,有时也会引入新的\(BUG\),假定有\(n(n<=20)\)个潜在\(BUG\),和\(m(m<=100)\)个补丁,每个补丁用两个长度为\(n\)的字符串表示,其中字符串的每个位置表示一个\(BUG\),第一个串表示打补丁之前的状态 (“-”表示该\(BUG\)必须不存在,“+”表示该补丁必须存在,0表示无所谓),第二串表示打补丁之后的状态 ("-"表示不存在,"+"表示存在,"0"表示不变)。每个补丁有一定的执行时间,你的任务是用最小的时间把所有BUG都存在的软件变得没有\(BUG\)。
【算法】
\(\text{隐式图}\)\(SPFA\)
【分析】
在任意时刻,每个\(BUG\)可能存在也可能不存在,所以可以用\(n\)位二进制串来表示当前软件的状态。打完补丁之后,软件的BUG状态会发生改变,对应状态转移。是不是很像动态规划?可惜动态规划是行不通的,因为状态经过多次转移之后可能会回到以前的状态,即状态图并不是DAG。如果直接用记忆化搜索,会出现无限递归。
正确的方法是把状态看成点,状态转移看成边,转化成图论中的最短路径问题,然后使用\(Dijkstra\)或\(Bellman-Ford\)算法进行求解。不过这道题和普通的最短路径问题不一样:节点很多,有\(2^n\)个,而且很多状态根本遇不到(即不管怎么打补丁,也不可能打成那种状态),所以没有必要先将原图存储好。
孩子咳嗽老不好, 怎么办呢?
这里介绍一种 "隐式图" 的方法,当需要得到某个点的所有边时,不是去读\(G[u]\),而是直接枚举这\(m\)个补丁是否打的上。不管是\(Dijkstra\)还是\(Bellman-Ford\)算法,这个方法都适用。
- 一些本题的其他小技巧
得到\(x\)的二进制右起第\(i\)位:
x>>(i-1)&1
把\(x\)二进制的右起第\(i\)位替换为\(a\)(\(a\)或\(0\)或\(1\)):
x^=(x&(1<<(i-1)))^(a<<(i-1))
【代码】
思路也说得很清楚了,这里就不写注释了
#include<bits/stdc++.h>
using namespace std;
const int MAXN=20+10,MAXM=100+10;
int n,m;
struct Node
{
int t;
int a[MAXN];
int b[MAXN];
}patch[MAXM];
int d[2000000];
int T;
inline void init(int k)
{
cin>>patch[k].t;
string s;
cin>>s;
for(int i=0;i<s.size();i++)
{
if(s[i]=='-')patch[k].a[i+1]=-1;
else if(s[i]=='0')patch[k].a[i+1]=0;
else patch[k].a[i+1]=1;
}
cin>>s;
for(int i=0;i<s.size();i++)
{
if(s[i]=='-')patch[k].b[i+1]=-1;
else if(s[i]=='0')patch[k].b[i+1]=0;
else patch[k].b[i+1]=1;
}
}
inline bool check(int sum,int k)
{
for(int i=1;i<=n;i++)
{
if(patch[k].a[i]==0)continue;
if(patch[k].a[i]==-1 && (sum>>(n-i)&1)==0 )continue;
if(patch[k].a[i]==1 && (sum>>(n-i)&1)==1 )continue;
return 0;
}
return 1;
}
inline int get(int sum,int k)
{
for(int i=1;i<=n;i++)
{
if(patch[k].b[i]==0)continue;
if(patch[k].b[i]==-1)sum^=(sum&(1<<(n-i)))^(0<<(n-i));
else sum^=(sum&(1<<(n-i)))^(1<<(n-i));
}
return sum;
}
inline void SPFA()
{
memset(d,0x3f,sizeof(d));
queue<int>q;
q.push((1<<n)-1);
d[(1<<n)-1]=0;
while(q.size())
{
int now=q.front();
//cout<<now<<endl;
q.pop();
for(int i=1;i<=m;i++)
{
if(!check(now,i))continue;
int x=get(now,i);
//cout<<x<<endl;
if(d[now]+patch[i].t<d[x])
{
d[x]=d[now]+patch[i].t;
q.push(x);
}
}
}
}
int main()
{
//ios::sync_with_stdio(false);
while(cin>>n>>m)
{
if(n==0&&m==0)break;
T++;
for(int i=1;i<=m;i++)
init(i);
//cout<<patch[1].a[1]<<" "<<patch[1].a[2]<<" "<<patch[1].a[3]<<endl;
SPFA();
printf("Product %d\n",T);
if(d[0]==0x3f3f3f3f)
printf("Bugs cannot be fixed.\n");
else
printf("Fastest sequence takes %d seconds.\n",d[0]);
cout<<endl;
}
return 0;
}
刘汝佳大法好!
洛谷 题解 UVA658 【这不是bug,而是特性 It's not a Bug, it's a Feature!】的更多相关文章
- 洛谷 题解 UVA572 【油田 Oil Deposits】
这是我在洛谷上的第一篇题解!!!!!!!! 这个其实很简单的 我是一只卡在了结束条件这里所以一直听取WA声一片,详细解释代码里见 #include<iostream> #include&l ...
- 洛谷 题解 P1600 【天天爱跑步】 (NOIP2016)
必须得说,这是一道难题(尤其对于我这样普及组205分的蒟蒻) 提交结果(NOIP2016 天天爱跑步): OJ名 编号 题目 状态 分数 总时间 内存 代码 / 答案文件 提交者 提交时间 Libre ...
- 洛谷题解P4314CPU监控--线段树
题目链接 https://www.luogu.org/problemnew/show/P4314 https://www.lydsy.com/JudgeOnline/problem.php?id=30 ...
- 洛谷题解 P1592 【互质】
原题传送门 题目描述 输入两个正整数n和k,求与n互质的第k个正整数. 输入格式 仅一行,为两个正整数n(≤10^6)和k(≤10^8). 输出格式 一个正整数,表示与n互质的第k个正整数. 输入输出 ...
- 洛谷题解 CF777A 【Shell Game】
同步题解 题目翻译(可能有童鞋没读懂题面上的翻译) 给你三张牌0,1,2. 最初选一张,然后依次进行n次交换,交换规则为:中间一张和左边的一张,中间一张和右边一张,中间一张和左边一张...... 最后 ...
- 洛谷题解 CF807A 【Is it rated?】
同步题解 题目 好吧,来说说思路: 1.先读入啦~(≧▽≦)/~啦啦啦 2.判断a[i]赛前赛后是否同分数,如果分数不同,则输出,return 0 . 3.如果同分数,则判断a[i]赛前(或赛后)是否 ...
- 洛谷题解 P1138 【第k小整数】
蒟蒻发题解了 说明:此题我用的方法为桶排(我翻了翻有人用了桶排只不过很难看出来,可能有些重复的,这个题只是作为一个专门的桶排来讲解吧) (不会算抄袭吧 ‘QWaWQ’) 简单来说(会的人跳过就行): ...
- 【洛谷题解】P2303 [SDOi2012]Longge的问题
题目传送门:链接. 能自己推出正确的式子的感觉真的很好! 题意简述: 求\(\sum_{i=1}^{n}gcd(i,n)\).\(n\leq 2^{32}\). 题解: 我们开始化简式子: \(\su ...
- 洛谷题解 P2865 【[USACO06NOV]路障Roadblocks】
链接:https://www.luogu.org/problemnew/show/P2865 题目描述 Bessie has moved to a small farm and sometimes e ...
随机推荐
- NuttX 构建系统
(嵌入式 实时操作系统 rtos nuttx 7.1 makefile) NuttX 构建系统 转载请注明出处: http://blog.csdn.net/zhumaill/article/detai ...
- JDBC数据源DBCP源代码情景分析
在之前的一篇博文从JDBC到commons-dbutils 中,我曾经写到,对于获取数据库连接,有一个解决方案,那就是数据源.业界用到的比较普遍的开源数据源解决方案有很多,DBCP是其中一种,今天,我 ...
- [转]TensorFlow如何进行时序预测
TensorFlow 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库.节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组 ...
- WCF 大文件传输配置
<bindings> <webHttpBinding> <!--这个是接收大数据加的,设置WCF服务器端数据接收上限参数,此处单位字节,故2147483647字节==2G ...
- PHP模拟POST提交数据并获得返回值之CURL方法(使用PHP extension,然后使用php_curl.dll,很不错)
今天公司做个东西,需要条用同事的接口,我的代码和他的代码不在同一个域下,但是都是子域. a.ifensi.com与b.ifensi.com的关系. 我需要传递一个关联数组过去,他那边给我返回一个jso ...
- JS注册事件
<html xmlns="http://www.w3.org/1999/xhtml"><head> <title></title&g ...
- 用树莓派和DS18B20做个汽车温度记录仪
原文:用树莓派和DS18B20做个汽车温度记录仪 用树莓派和DS18B20做个汽车温度记录仪[原创] 很想知道夏日阳光暴晒下,汽车内的最高温度以及温度的变化情况.觉得用树莓派和DS18B20来实现应该 ...
- Styling a ListView with a Horizontal ItemsPanel and a Header
原文http://eblog.cloudplush.com/2012/05/23/styling-a-listview-with-a-horizontal-itemspanel-and-a-heade ...
- WPF MVVM+EF增删改查 简单示例(二) 1对1 映射
WPF MVVM+EF增删改查 简单示例(一)实现了对学生信息的管理. 现在需求发生变更,在录入学生资料的时候同时需要录入学生的图片信息,并且一名学生只能有一张图片资料.并可对学生的图片资料进行更新. ...
- Debian下编译安装驱动模块
在Linux下,我们常有需要自己来编译安装驱动模块的情况,例如要安装显卡驱动,要安装无线驱动,有的时候某个程序的安装使用与需要安装相应的驱动模块.Debian Linux下的生活本已十分简单,使用ap ...