HDU 5094 Maze & HDU 4845 拯救大兵瑞恩 (BFS + 状压)

题意:给你一个n*m的迷宫,地图中有一些障碍不能走,还有p种门,要过门首先得拿到跟这扇门同类型的钥匙。

问从(1,1)到(n,m)最短时间。(1<= n, m <=50, 0<= p <=10)


思路:没有门的时候都会做,一个bfs就行,现在只不过是多了门这种情况。

解决办法:

book[x][y][sta] 表示(x, y)这个点在sta状态下是否已经走过,sta表示拥有钥匙情况。

bar[x1][y1][x2][y2] 表示(x1, y1)到(y1, y2)是否有墙

sth[x1][y1][x2][y2] 表示(x1, y1)到(x2, y2)存在哪种门,0表示没有

key[x][y] 表示(x, y)处有什么钥匙

有了这些处理,再去做bfs就可以了。

注意有些点可能有多个钥匙;墙和门是双向的。


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 51;
const int maxm = 11;
bool book[maxn][maxn][1<<maxm];
bool bar[maxn][maxn][maxn][maxn];
int sth[maxn][maxn][maxn][maxn];
int key[maxn][maxn];
int n, m, p, k; //k men\qiang, p kind

struct node
{
    int x, y, t, k;
    node() {}
    node(int xx, int yy, int tt, int kk): x(xx), y(yy), t(tt), k(kk) {}
};

int bfs()
{
    int Next[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
    memset(book, 0, sizeof(book));
    queue<node> q;
    int tmp = 0;
    if(key[1][1])
        tmp |= key[1][1];
    q.push(node(1, 1, 0, tmp));
    book[1][1][tmp] = 1;
    while(!q.empty())
    {
        node u = q.front(); q.pop();
        int x = u.x, y = u.y, t = u.t, k = u.k;
        if(x == n && y == m) return t;
        for(int i = 0; i < 4; i++)
        {
            int tx = x+Next[i][0];
            int ty = y+Next[i][1];
            if(tx >= 1 && ty >= 1 && tx <= n && ty <= m && !bar[x][y][tx][ty] && !book[tx][ty][k])
            {
                if(!sth[x][y][tx][ty] || (k>>(sth[x][y][tx][ty]-1))&1)
                {
                    book[tx][ty][k] = 1;
                    book[tx][ty][k|key[tx][ty]] = 1;
                    q.push(node(tx, ty, t+1, k|key[tx][ty]));
                }
            }
        }
    }
    return -1;
}

int main(void)
{
    while(cin >> n >> m >> p)
    {
        memset(key, 0, sizeof(key));
        memset(bar, 0, sizeof(bar));
        memset(sth, 0, sizeof(sth));
        scanf("%d", &k);
        for(int i = 1; i <= k; i++)
        {
            int x1, y1, x2, y2, z;
            scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &z);
            if(!z) bar[x1][y1][x2][y2] = bar[x2][y2][x1][y1] = 1;
            else sth[x1][y1][x2][y2] = sth[x2][y2][x1][y1] = z;
        }
        scanf("%d", &k);
        for(int i = 1; i <= k; i++)
        {
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            key[x][y] |= (1<<(z-1));
        }
        printf("%d\n", bfs());
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值