HDU 5025 Saving Tang Monk(bfs+状压) 【openjudge】

127 篇文章 0 订阅
85 篇文章 2 订阅

Saving Tang Monk

问题分析

本题就是属于拿钥匙去开门的 bfs b f s 类题目。
题意:孙悟空必须拿到 n n 个钥匙才能救出唐僧,但是期间如果遇到蛇怪需要多花一分钟去打败她们,并且在拿到第i个钥匙之前必须先拿到第 i1 i − 1 个钥匙,问最少的花费时间。

这题就麻烦在三个地方,
一、同种钥匙可能有多个,拿完钥匙的地方仍然可以走,所以需要加一维钥匙的状态来判重。
二、因为打败蛇怪需要多花费时间,所以肯定要优先走不经过蛇怪的最短路,优先队列解决。
三、打过蛇怪的地方仍然可以走动,所以需要判断蛇洞里的蛇怪 dead d e a d 没有,所以需要节点加一个打蛇怪的状态 (snake) ( 假 设 为 s n a k e ) 。就比如用 0,1,2,3,4... 0 , 1 , 2 , 3 , 4... 给蛇编号的,判断 i i 号蛇怪是否死亡就用当前的状态snake&(1<<i),如果结果等于0则说明i蛇怪还没有 dead d e a d ,否则就是 dead d e a d

#include <bits/stdc++.h>

struct node {
    int x, y, step, snake, key;

    bool operator<(const node &u) const {
        return step > u.step;
    }
};

const int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
bool vis[111][111][11];
char a[111][111];
int n, m, snakeLoc[111][111];

int rec(int stx, int sty, int desx, int desy) {
    std::priority_queue<node> pq;
    node cur, nxt;
    cur.x = stx, cur.y = sty, cur.step = cur.key = cur.snake = 0;
    pq.push(cur);
    while (!pq.empty()) {
        cur = pq.top();
        pq.pop();
        if (cur.x == desx && cur.y == desy && cur.key == m)
            return cur.step;
        for (int i = 0; i < 4; ++i) {
            int tx = cur.x + dir[i][0];
            int ty = cur.y + dir[i][1];
            int key = cur.key, step = cur.step + 1, snake = cur.snake;
            if (a[tx][ty] == cur.key + '1')
                key++;
            if (tx < 0 || tx >= n || ty < 0 || ty >= n || vis[tx][ty][key] || a[tx][ty] == '#')
                continue;
            if (a[tx][ty] == 'S' && ((snake & (1 << snakeLoc[tx][ty])) == 0)) //if it is a alive snake
                step++, snake |= (1 << snakeLoc[tx][ty]);
            vis[tx][ty][key] = 1;
            nxt = {tx, ty, step, snake, key};
            pq.push(nxt);
        }
    }
    return -1;
}

int main() {
    while (~scanf("%d%d", &n, &m) && (n + m)) {
        int stx, sty, desx, desy, cnt = 0;
        memset(vis, 0, sizeof vis);
        memset(snakeLoc, 0, sizeof(snakeLoc));
        for (int i = 0; i < n; ++i)
            for (int j = 0; j < n; ++j) {
                scanf(" %c", &a[i][j]);
                if (a[i][j] == 'K') stx = i, sty = j;
                if (a[i][j] == 'T') desx = i, desy = j;
                if (a[i][j] == 'S') snakeLoc[i][j] = cnt++;
            }
        int ans = rec(stx, sty, desx, desy);
        if (ans == -1) puts("impossible");
        else printf("%d\n", ans);
    }
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值