luogu4011 孤岛营救问题 分层图

关键词:分层图 状态压缩 最短路径

分层图:现在要求从起点到终点的最优路线,但受到手里拿着哪些钥匙的影响,最优路线不单纯了。因此,决定一个节点、一条边的存在的数中应当增加一个手中拿有钥匙的状态。这样就相当于把一张图按拿有钥匙的状态数分出了很多层。

状态压缩:手中拿有钥匙的状态可以压缩到一个整数中。

最短路径:手中拿有钥匙的状态固定了,在分层图中我们就不再用得着走回头路了。这样就转化成了最短路径问题。

#include <cstdio>
#include <cassert>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

const int MAX_X = 20, MAX_Y = 20, MAX_KEY = 20, MAX_S = 1 << 11, INF = 0x3f3f3f3f;
int Dist[MAX_X][MAX_Y][MAX_S];
int Key[MAX_X][MAX_Y];
int Gate[MAX_X][MAX_Y][MAX_X][MAX_Y];
int TotX, TotY;
const int xNext[] = { 0,-1,0,0,1 }, yNext[] = { 0, 0,1,-1,0 };

struct Queue
{
    int xs[MAX_X*MAX_Y*MAX_S], ys[MAX_X*MAX_Y*MAX_S], ss[MAX_X*MAX_Y*MAX_S];
    int head, tail;
    Queue() { head = tail = 0; }
    void push(int x, int y, int s) { xs[tail] = x; ys[tail] = y; ss[tail] = s; tail++; }
    void pop() { head++; }
    bool empty() { return head == tail; }
    int frontX() { return xs[head]; }
    int frontY() { return ys[head]; }
    int frontS() { return ss[head]; }
};

int Bfs()
{
    int ans = INF;
    static Queue q;
    Dist[1][1][Key[1][1]] = 0;
    q.push(1, 1, Key[1][1]);
    while (!q.empty())
    {
        int x = q.frontX(), y = q.frontY(), s = q.frontS();
        q.pop();
        Dist[x][y][s | Key[x][y]] = Dist[x][y][s];
        s |= Key[x][y];
        for (int p = 1; p <= 4; p++)
        {
            int x2 = x + xNext[p], y2 = y + yNext[p];
            if (x2 >= 1 && x2 <= TotX && y2 >= 1 && y2 <= TotY &&
                Dist[x2][y2][s]==INF &&
                (Gate[x][y][x2][y2] == -1 || s&(1 << Gate[x][y][x2][y2])))
            {
                Dist[x2][y2][s] = Dist[x][y][s] + 1;
                q.push(x2, y2, s);
                if (x2 == TotX&&y2 == TotY)
                    ans = min(ans, Dist[x2][y2][s]);
            }
        }
    }
    return ans;
}

int main()
{
#ifdef _DEBUG
    freopen("c:\\noi\\source\\input.txt", "r", stdin);
#endif
    int totObs, totKeySort, x1, x2, y1, y2, gate, totKey, key;
    memset(Gate, -1, sizeof(Gate));
    memset(Dist, INF, sizeof(Dist));
    scanf("%d%d%d%d", &TotX, &TotY, &totKeySort, &totObs);
    while (totObs--)
    {
        scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &gate);
        Gate[x1][y1][x2][y2] = Gate[x2][y2][x1][y1] = gate;
    }
    scanf("%d", &totKey);
    while (totKey--)
    {
        scanf("%d%d%d", &x1, &y1, &key);
        if (key >= 32)
            printf("error\n");
        Key[x1][y1] |= 1 << key;
    }
    int ans = Bfs();
    if (ans == INF)
        printf("-1\n");
    else
        printf("%d\n", ans);
    return 0;
}

 

posted @ 2018-02-13 15:25  headboy2002  阅读(144)  评论(0编辑  收藏  举报