POJ 2908 Quantum(BFS + 优先队列)

题意:

初始串经过一系列操作可以变换成目标串,每一次操作需要耗费一定的能量,求最小的能量。

思路:

1. 这一题同样采取 BFS 但是求的结果并不是最短路径,而是最小的耗能。其实也就是变换下思路,每次深搜之后把耗能最小的先出队列即可;

2. 这样的话可以把题目转换成优先队列的 dijstra 算法, 从源点到目标点的距离 -> 这里的点的变换即是状态的变换;

3. 题目中有个小 trick 使得一般的优先队列 BFS 算法无效,考虑如下 case:

   FFFF 10 , FFNN 1 , NNFF 1 , 0000 -> 1111 显然最小功耗是 2 而非 10,所以采用 dijstra 算法是合适的。

4. 由于题目中 L <= 20,所以在本题采用位运算会使过程变得十分优美,最终代码跑到了 141ms ;


#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;

struct ST {
    int state, cost;
    ST(int _state, int _cost) : state(_state), cost(_cost) {}
    bool operator < (const ST& other) const { return cost > other.cost; }
};

struct OP {
    int op_and, op_or, op_xor;
    int cost;
} op[40];

const int INFS = 0x3fffffff;
int L, N, M, dis[1<<20];
bool vis[1<<20];

int bfs(int s, int t) {
    priority_queue<ST> Q;
    Q.push(ST(s, 0));

    for (int i = 0; i < 1<<L; i++)
        dis[i] = INFS, vis[i] = false;
    dis[s] = 0;

    while (!Q.empty()) {
        ST u = Q.top();
        Q.pop();

        if (u.state == t) 
            return u.cost;
        vis[s] = true;

        for (int i = 0; i < N; i++) {
            int v = u.state;
            v &= op[i].op_and;
            v |= op[i].op_or;
            v ^= op[i].op_xor;
            if (!vis[v] && dis[v] > u.cost + op[i].cost) {
                dis[v] = u.cost + op[i].cost;
                Q.push(ST(v, dis[v]));
            }
        }
    }
    return -1;
}

int main() {
    int cases;
    scanf("%d", &cases);
    while (cases--) {
        scanf("%d%d%d", &L, &N, &M);
        for (int i = 0; i < N; i++) {
            char s[30];
            scanf("%s%d", s, &op[i].cost);
            op[i].op_and = op[i].op_or = op[i].op_xor = 0;
            for (int j = 0; s[j]; j++) {
                op[i].op_and <<= 1;
                op[i].op_or <<= 1;
                op[i].op_xor <<= 1;
                if (s[j] == 'N') 
                    op[i].op_or |= 0;
                else if (s[j] == 'C') 
                    op[i].op_and |= 1;
                else if (s[j] == 'F')
                    op[i].op_xor |= 1;
                else if (s[j] == 'S')
                    op[i].op_or |= 1;
            }
            op[i].op_and = ~op[i].op_and;
        }
        for (int i = 0; i < M; i++) {
            char src[30], dst[30];
            int u = 0, v = 0;
            scanf("%s%s", src, dst);
            for (int j = 0; src[j]; j++)
                u <<= 1, u |= (src[j] - '0');
            for (int j = 0; dst[j]; j++)
                v <<= 1, v |= (dst[j] - '0');
            int ans = bfs(u, v);
            if (ans != -1) 
                printf("%d", ans);
            else 
                printf("NP");
            printf("%c", i == M-1 ? '\n' : ' ');
        }
    }
    return 0;
}
 
原文地址:https://www.cnblogs.com/kedebug/p/2986503.html