UVa 658 It's not a Bug, it's a Feature! 位运算技巧+dijkstra优先队列优化

/**
*     我真服了。 UVa 数组越界只返回WA,不给RE  这题debug了两天,WA了两天
*  最后发现就是数组越界的问题!!
*     做这题学了个很不错的位运算技巧:
*   这样写下来时间还是比较多,后来看了别人的解题报告,发现在判定当前状态是否可以转换的时候可以直接用位运算去操作:

    ①判定某些位置是否为1,如判定2、4位置为1,则转化为判断x|0101是否等于x。

    ②判定某些位置是否为0,如判定2、4位置为0,则转化为判断x&1010是否等于x。

    ③将某些位置转化为1,如2、4位置转化为1,则令x=x|0101。

    ④将某些位置转化为0,如2、4位置转化为0,则令x=x&1010。
*   摘自 http://www.cnblogs.com/staginner/archive/2011/10/25/2223489.html
*/

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <string>
#include <queue>
#include <map>
#include <vector>
#include <algorithm>
#define DEBUG 0
#define INF 0x3fffffff
#define MAXS 25
#define MAXM 105

typedef long long LL;
using namespace std;
int n, m;
int dis[1 << MAXS], vis[1 << MAXS], posi1[MAXM], negt1[MAXM], posi2[MAXM], negt2[MAXM], times[MAXM];
queue<int> q;

struct Node {
    int v, t;
    Node() {}
    Node(int vv, int tt) {v = vv; t = tt;}
    bool operator < (const Node &a) const {
        return t > a.t;
    }
};
priority_queue<Node> pq;

void init() {
    while(!q.empty()) q.pop();
    for(int i = 0; i < MAXM; i ++)
        posi1[i] = posi2[i] = negt1[i] = negt2[i] = 0;
    int len = 1 << n;
    for(int i = 0; i < len; i ++) {
        dis[i] = INF;
        vis[i] = 0;
    }
}

void change(char *str1, char *str2, int x) {
    for(int i = 0; str1[i]; i ++) {
        if(str1[i] == '+')
            posi1[x] |= (1 << i);
        if(str1[i] != '-')
            negt1[x] |= (1 << i);
    }
    for(int i = 0; str2[i]; i ++) {
        if(str2[i] == '+')
            posi2[x] |= (1 << i);
        if(str2[i] != '-')
            negt2[x] |= (1 << i);
    }
}

void dijkstra() {
    while(!pq.empty()) pq.pop();
    int start = (1 << n) - 1;
    pq.push(Node(start, 0));
    dis[start] = 0;
    if(DEBUG)
        printf("start: %d\n", start);
    while(!pq.empty()) {
        Node cur = pq.top(); pq.pop();
        if(DEBUG) printf("cur: %d\n", cur.v);
        if(vis[cur.v]) continue;
        vis[cur.v] = 1;
        if(cur.v == 0) {
            break;
        }

        for(int i = 0; i < m; i ++) {
            int next = cur.v;
            if((cur.v | posi1[i]) == cur.v && (cur.v & negt1[i]) == cur.v) {
                next |= posi2[i];
                next &= negt2[i];
                if(dis[next] > dis[cur.v] + times[i]) {
                    dis[next] = dis[cur.v] + times[i];
                    pq.push(Node(next, dis[next]));
                    if(DEBUG)
                        printf("patch: %d  dis[%d]: %d\n", i, next, dis[next]);
                }
            }
        }
    }

    if(dis[0] == INF) printf("Bugs cannot be fixed.\n\n");
    else printf("Fastest sequence takes %d seconds.\n\n", dis[0]);
}

int main()
{
    int product = 1;
    while(scanf("%d%d", &n, &m), n + m) {
        printf("Product %d\n", product ++);
        init();
        char str1[MAXS], str2[MAXS];
        for(int i = 0; i < m; i ++) {
            scanf("%d%s%s", ×[i], str1, str2);
            change(str1, str2, i);
        }
        dijkstra();
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值