题意:有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! (最短路,经典)的更多相关文章

  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!

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

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

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

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

  5. [有意思]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 ...

  6. 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   ...

  7. 【最短路】【位运算】It's not a Bug, it's a Feature!

    [Uva658] It's not a Bug, it's a Feature! 题目略 UVA658 Problem PDF上有 试题分析:     本题可以看到:有<=20个潜在的BUG,那 ...

  8. uva_658_It&#39;s not a Bug, it&#39;s a Feature!(最短路)

    It's not a Bug, it's a Feature! Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & ...

  9. UVa 658 (Dijkstra) It's not a Bug, it's a Feature!

    题意: 有n个BUG和m个补丁,每个补丁用一个串表示打补丁前的状态要满足的要求,第二个串表示打完后对补丁的影响,还有打补丁所需要的时间. 求修复所有BUG的最短时间. 分析: 可以用n个二进制位表示这 ...

随机推荐

  1. 【BZOJ】【2768】【JLOI2010】冠军调查

    网络流/最小割 我不会告诉你这题跟 BZOJ 1934 是一模一样的……包括数据范围…… /****************************************************** ...

  2. 【POJ】【3164】Commond Network

    最小树形图 最小树形图模板题,朱-刘算法. 题解:http://blog.csdn.net/shuangde800/article/details/8039359 这位大神代码写的非常通俗易懂,而且这 ...

  3. [51 nod]1009 数字1的数量

    1009 数字1的数量 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题 给定一个十进制正整数N,写下从1开始,到N的所有正数,计算出其中出现所有1的个数.   例如: ...

  4. linux源代码阅读笔记 free_page_tables()分析

    /* 77 * This function frees a continuos block of page tables, as needed 78 * by 'exit()'. As does co ...

  5. POJ 3045

    Cow Acrobats Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2302   Accepted: 912 Descr ...

  6. java基础知识回顾之java Thread类学习(五)--java多线程安全问题(锁)同步的前提

    这里举个例子讲解,同步synchronized在什么地方加,以及同步的前提: * 1.必须要有两个以上的线程,才需要同步. * 2.必须是多个线程使用同一个锁. * 3.必须保证同步中只能有一个线程在 ...

  7. TortoiseSVN文件夹及文件图标不显示解决方法(转发)

    地址:http://blog.csdn.net/lishehe/article/details/8257545 由于自己的电脑是win7(64位)的,系统安装TortoiseSVN之后,其他的功能都能 ...

  8. cognos8.3 sample在DB2里的安装

    db2 create db c83 alias c83 using codeset UTF-8 territory CA 创建sample数据库 db2set db2codepage= db2 cha ...

  9. 欧拉工程第69题:Totient maximum

    题目链接 欧拉函数φ(n)(有时也叫做phi函数)可以用来计算小于n 的数字中与n互质的数字的个数. 当n小于1,000,000时候,n/φ(n)最大值时候的n. 欧拉函数维基百科链接 这里的是p是n ...

  10. 转贴: A Simple c# Wrapper for ffMpeg

    原帖地址:http://jasonjano.wordpress.com/2010/02/09/a-simple-c-wrapper-for-ffmpeg/ A Simple c# Wrapper fo ...