zoukankan      html  css  js  c++  java
  • 洛谷 P2761 软件补丁问题

    题目描述

    T 公司发现其研制的一个软件中有 n 个错误,随即为该软件发放了一批共 m 个补丁程序。每一个补丁程序都有其特定的适用环境,某个补丁只有在软件中包含某些错误而同时又不包含另一些错误时才可以使用。一个补丁在排除某些错误的同时,往往会加入另一些错误。

    换句话说,对于每一个补丁 i,都有 2 个与之相应的错误集合 B1[i]和 B2[i],使得仅当软件包含 B1[i]中的所有错误,而不包含 B2[i]中的任何错误时,才可以使用补丁 i。补丁 i 将修复软件中的某些错误 F1[i],而同时加入另一些错误 F2[i]。另外,每个补丁都耗费一定的时间。

    试设计一个算法,利用 T 公司提供的 m 个补丁程序将原软件修复成一个没有错误的软件,并使修复后的软件耗时最少。对于给定的 n 个错误和 m 个补丁程序,找到总耗时最少的软件修复方案。

    1<=n<=20, 1<=m<=100

    问题分析:

    由于n的范围很小,我们可以把每一个漏洞的状态用0和1来表示,即将当前系统状态用一个01的串来表示,状态压缩。

    DP即可,但是由于DP状态会有1e6种,每种转移要m次,复杂度太大了。。。所以用最短路解决问题,可以减少一些不会到达的状态。

    起点为所有漏洞都未被修复的状态(11.....11),终点为所有漏洞都已被修复的状态(00....00).

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    char s[25];
    int t[105];
    int sta1[105],sta2[105];
    int res1[105],res2[105];
    int dis[2100000],vis[2100000];
    queue<int> Q;
    int main()
    {
        memset(dis,0x3f,sizeof(dis));
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i = 1;i <= m;++i){
            scanf("%d",&t[i]);
            scanf("%s",s);
            for(int j = 0;j < n;++j){
                if(s[j] == '+') sta1[i] += (1<<j);
                else if(s[j] == '-') sta2[i] += (1<<j);
            }
            scanf("%s",s);
            for(int j = 0;j < n;++j){
                if(s[j] == '+') res2[i] += (1<<j);
                else if(s[j] == '-') res1[i] += (1<<j);
            }
        }
        int now = (1<<n)-1;
        dis[now] = 0;
        Q.push(now);
        vis[now] = 1;
        while(!Q.empty()){
            now = Q.front();
            Q.pop();
        
            for(int i = 1;i <= m;++i){
                if((now & sta1[i]) != sta1[i]) continue;
                if((~now & sta2[i]) != sta2[i]) continue;
                int tmp = (now  & (~res1[i])) | res2[i];           
                if(dis[tmp] > dis[now] + t[i]){
                    dis[tmp] = dis[now] + t[i];
                    if(!vis[tmp]) vis[tmp] = 1,Q.push(tmp);
                }
            }
            vis[now] = 0;
        }
        if(dis[0] == 0x3f3f3f3f) puts("0");
        else printf("%d\n",dis[0]);
        return 0;
    }
  • 相关阅读:
    img标签为什么可以设置宽高
    高度和宽度的操作
    自增自减运算符
    读取标签内容:innerHTML和innerText的区别 text()和html()的区别
    js中的常用方法
    js中style,currentStyle和getComputedStyle的区别以及获取css操作方法(考虑兼容性和局限性)
    IE盒模型与W3C盒模型区别
    css四种定位方式及其区别
    css隐藏元素的方法何区别
    Hibernate之HQL
  • 原文地址:https://www.cnblogs.com/obob/p/9567451.html
Copyright © 2011-2022 走看看