UVA 658 It's not a Bug, it's a Feature!

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

很棒的一道最短路的题 ,首先是得能看出是最短路。。。要不是在最短路专题里做到它,肯定就想拿状压dp去做了,但会成环,所有并不能用状压dp去做,正确的方法 就想刘汝佳书上说的那样,把状态看出节点,但不预先处理出边,而是在读到点u时,遍历所有的补丁来处理出边。注意处理边是不能太暴力,要跟状压dp里处理状态一样,用2进制的各种运算来处理,才不会T掉。

这里重点解释一下go()里的 补丁处理 输入为当前状态 和补丁序号 每个补丁里面存 a0是补丁要求状态里0(0是有bug)的位置,所有应该是0的地方在2进制的对应位赋成1 这样当前状态和a0取& 就是把这些应该为0的位取出来 ,为0 才满足补丁要求。其他操作同理。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#define scnaf scanf
#define cahr char
#define bug puts("bugbugbug");
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int inf=214748367;
const int M=1000+5;
//挺实用的 复杂度O(Elog((N)) 其实要小很多
priority_queue<pii,vector<pii>,greater<pii> >q;
int n,m,w;
struct DEBUG
{
    int a0,a1,b0,b1;
    int v;
} bu[105];
int d[5548576];
int now[105]= {0};
int go(int u,int id)
{
    if((u&bu[id].a0)!=0)return -1;
    if((u&bu[id].a1)!=bu[id].a1)return -1;
    u|=bu[id].b1;
    u-=u&bu[id].b0;
    return u;
}
int Dijkstra(int u)
{
    while(!q.empty())q.pop();
    for(int i=0; i<=n; i++) d[i]=i==u?0:inf;
    q.push({0,u});
    while(!q.empty())
    {
        pii x=q.top();
        q.pop();
       // if(x.first>d[n])return 0;
        if(x.first!=d[x.second])continue;
        int u=x.second;
        for(int i=0; i<m; i++)
        {
            int e=go(u,i);
           // cout<<u<<" "<<i<<" "<<e<<" "<<endl;
            if(e==-1)continue;
            if(d[e]>d[u]+bu[i].v)
            {
                d[e]=d[u]+bu[i].v;
                q.push({d[e],e});
            }
        }
    }
}
int pow(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1)res*=a;
        a*=a;
        b>>=1;
    }
    return res;
}
char A[105],B[105];
// + = 0 = bug
int main()
{
    int cnt=0;
    while(~scnaf("%d%d",&w,&m)&&w+m)
    {
        n=pow(2,w)-1;
        for(int i=0; i<m; i++)
        {
            scanf("%d%s%s",&bu[i].v,A,B);
            int& a0=bu[i].a0;
            int& a1=bu[i].a1;
            int& b0=bu[i].b0;
            int& b1=bu[i].b1;
            a1=a0=b1=b0=0;
            for(int i=0; i<w; i++)
            {
                a0*=2;
                a1*=2;
                b0*=2;
                b1*=2;
                if(A[i]=='+')a0++;
                else if(A[i]=='-')a1++;
                if(B[i]=='+')b0++;
                else if(B[i]=='-') b1++;
            }
        }
        Dijkstra(0);
        printf("Product %d\n",++cnt);
        if(d[n]==inf)
            puts("Bugs cannot be fixed.");
        else
            printf("Fastest sequence takes %d seconds.\n",d[n]);
        puts("");
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值