uva658

题目描述:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=22169

/*
solution:   相比与uva12661,此题是在图的结点上动了手脚。用一个n位二进制串来表示当前软件的状态,每次打完补丁后,
                该状态就发生改变。所以可以把该状态看成结点,补丁打上后发生状态转移的过程看成边,就可转化成最短路问题。
                但这道题不能硬套模板。需要做些变化。如note第一点。

note:   1.注意需要得到从任意结点u出发的所有边时,不是像模板里面读G[u],而是直接列举所有补丁,看看是否能够打上。
           2.注意判断补丁能否打上时用的位运算表示的含义。
           3.题意是关键,此题容易理解错。
           4.注意输出格式。UvaOJ里面的PE(输出格式错误)有一部分是直接给的WA(错误答案)信息。不要少末尾句号。

date:   2016/4/22

add:    附上对题意的中文概括
        假定有n个潜在的bug和m个补丁,每个补丁用长为n的字符串表示。首先输入bug数目以及补丁数目。然后就是对m
        个补丁的描述,共有m行。每行首先是一个整数,表明打该补丁所需要的时间。然后是两个字符串,地一个字符串
        是对软件的描述,只有软件处于该状态下才能打该补丁该字符串的每一个位置代表bug状态(-代表该位置没bug,+代
        表该位置有bug,0表示该位置无论有没有bug都可打补丁)。然后第二个字符串是对打上补丁后软件状态的描述
        -代表该位置上的bug已经被修复,+表示该位置又引入了一个新的bug, 0表示该位置跟原来状态一样)。要求用最少
        时间完成对软件的修复,即将所有位置全都置为0.
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;
const int maxBug = 20;
const int maxPatch = 105;
const int INF = 1000000000;

int n, m, t[maxPatch], d[1<<maxBug], vis[1<<maxBug];
char before[maxPatch][maxBug+5], after[maxPatch][maxBug+5];

struct Node {
    int bug, dist;  //dist表示到源点的距离
    bool operator < (const Node& rhs) const {
        return dist > rhs.dist;
    }
};

int dijkstra() {
    for(int i = 0; i < (1<<n); i++)  {  //初始化
            d[i] = INF;
            vis[i] = 0;
    }
    priority_queue<Node> q;
    Node start;
    start.bug = (1<<n) - 1; //n右移一位表示2的n次方。
    start.dist = 0;
    q.push(start);
    d[start.bug] = 0;

    while(!q.empty()) {
        Node x = q.top();   q.pop();
        if(x.bug == 0)  return x.dist;  //说明所有bug已经修复好,返回答案。
        if(vis[x.bug])  continue;
        vis[x.bug] = 1;
        for(int i = 0; i < m; i++) {
            bool patchable = true;  //首先判断能否该补丁是否适合。
            for(int j = 0; j < n; j++) {
                if(before[i][j] == '-' && (x.bug & (1<<j)))   {patchable = false; break;}   //x.bug & (1<<j)意思是从x.bug的二进制位中取出第j位(j从0开始)
                if(before[i][j] == '+' && !(x.bug & (1<<j)))  {patchable = false; break;}
            }
            if(!patchable)  continue;   //若不适合就换另外补丁。

            Node next;  //利用所选择的补丁对其进行修复
            next.bug = x.bug;
            next.dist = x.dist + t[i];
            for(int j = 0; j < n; j++) {
                if(after[i][j] == '-')  next.bug &= ~(1<<j);    //将next.bug的二进制位中的第j位置为0
                if(after[i][j] == '+')  next.bug |= (1<<j);     //将next.bug的二进制位中的第j位置为1
            }   //忽略为0的状况
            int &D = d[next.bug];   //注意“引用”
            if(next.dist < D) { //松弛操作,注意是引用,因此原变量的值也应该改变
                D = next.dist;
                q.push(next);
            }
        }
    }
    return -1;
}

int main()
{
   //freopen("input.txt", "r", stdin);
    int T = 0;
    while(scanf("%d%d", &n, &m) == 2 && n) {
        for(int i = 0; i < m; i++)
            scanf("%d%s%s", &t[i], before[i], after[i]);    //读入数据

        int ans = dijkstra();
        printf("Product %d\n", ++T);
        if(ans < 0) printf("Bugs cannot be fixed.\n\n");    //需要注意题目要求的输出格式
        else printf("Fastest sequence takes %d seconds.\n\n", ans);
    }
    return 0;
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值