欢迎访问我的Uva题解目录 https://blog.csdn.net/richenyunqi/article/details/81149109

题目描述

例题11-6 这不是bug,而是特性(It's not a Bug, it's a Feature!, UVa 658)

题意解析

补丁在修正bug时,有时也会引入新的bug。假定有n(n≤20)个潜在bug和m(m≤100)个补丁,每个补丁用两个长度为n的字符串表示,其中字符串的每个位置表示一个bug。第一个串表示打补丁之前的状态(“-”表示该bug必须不存在,“+”表示必须存在,0表示无所谓),第二个串表示打补丁之后的状态(“-”表示不存在,“+”表示存在,0表示不变)。每个补丁都有一个执行时间,你的任务是用最少的时间把一个所有bug都存在的软件通过打补丁的方式变得没有bug。一个补丁可以打多次。

算法设计

可以用一个n位二进制串表示当前软件存在的bug的“状态”。以这样的状态作为结点,状态转移看成边,转化成图论中的最短路径问题,然后使用Dijkstra算法求解。不过这道题和普通的最短路径问题不一样:结点很多,多达2n2^n个,而且很多状态根本遇不到(即不管怎么打补丁,也不可能打成那个状态),所以没有必要提前把图储存好。在Dijkstra算法求解过程中,当需要得到某个结点u出发的所有边时,不是去读G[u],而是直接枚举所有m个补丁,看看是否能打得上。

注意点

  1. 每个结点bug的状态不要用string来存储,这样会相当耗时,可以用bitset来存储,bitset其实就是一串二进制位,关于它的用法可以参考bitset - C++ Reference。其实我们完全可以把bitset当作更高效的bool类型数组来使用。
  2. 本题中尽量使用scanf读入,不要使用cin,因为本题测试数据量很大,cin读入非常耗时。

C++代码

#include<bits/stdc++.h>
using namespace std;
struct Patch{//补丁
    int time;
    char s1[25],s2[25];
};
typedef pair<int,int> pis;
bool match(const bitset<32>&b,const Patch&p){//当前状态与补丁是否匹配
    for(int i=0;p.s1[i]!='\0';++i)
        if((p.s1[i]=='+'&&!b[i])||(p.s1[i]=='-'&&b[i]))
            return false;
    return true;
}
int fix(bitset<32>&b,const Patch&p){//打补丁,返回打好补丁后的状态
    for(int i=0;i<p.s2[i]!='\0';++i){
        if(p.s2[i]=='+')
            b[i]=true;
        else if(p.s2[i]=='-')
            b[i]=false;
    }
    return b.to_ulong();
}
int main(){
    int n,m;
    for(int ii=1;~scanf("%d%d",&n,&m)&&n!=0;++ii){
        vector<Patch>patches(m);//存储所有的补丁
        for(int i=0;i<m;++i)
            scanf("%d%s%s",&patches[i].time,patches[i].s1,patches[i].s2);
        unordered_map<int,int>dis={{(1<<n)-1,0}};//存储状态及对应花费的最短时间
        priority_queue<pis,vector<pis>,greater<pis>>pq;
        pq.push({0,(1<<n)-1});
        while(!pq.empty()){//Dijkstra算法
            pis t=pq.top();
            pq.pop();
            if(dis[t.second]!=t.first)
                continue;
            for(Patch p:patches){
                bitset<32>b(t.second);
                if(match(b,p)){
                    int s=fix(b,p);
                    if(dis.find(s)==dis.end()||dis[s]>t.first+p.time){
                        dis[s]=t.first+p.time;
                        pq.push({t.first+p.time,s});
                    }
                }
            }
        }
        printf("Product %d\n",ii);
        if(dis.find(0)!=dis.end())
            printf("Fastest sequence takes %d seconds.\n\n",dis[0]);
        else
            printf("Bugs cannot be fixed.\n\n");
    }
    return 0;
}

相关文章: