HDU 4845 拯救大兵瑞恩 基本状态压缩bfs

题意:1944年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩。瑞恩被关押在一个迷宫里,迷宫地形复杂,但是幸好麦克得到了迷宫的地形图。
   迷宫的外形是一个长方形,其在南北方向被划分为N行,在东西方向被划分为M列,于是整个迷宫被划分为N*M个单元。我们用一个有序数对(单元的行号,单元的列号)来表示单元位置。南北或东西方向相邻的两个单元之间可以互通,或者存在一扇锁着的门,又或者存在一堵不可逾越的墙。迷宫中有一些单元存放着钥匙,并且所有的门被分为P类,打开同一类的门的钥匙相同,打开不同类的门的钥匙不同。
   大兵瑞恩被关押在迷宫的东南角,即(N,M)单元里,并已经昏迷。迷宫只有一个入口,在西北角,也就是说,麦克可以直接进入(1,1)单元。另外,麦克从一个单元移动到另一个相邻单元的时间为1,拿取所在单元的钥匙的时间以及用钥匙开门的时间忽略不计。
   你的任务是帮助麦克以最快的方式抵达瑞恩所在单元,营救大兵瑞恩。


想法:典型的状态压缩,把麦克的位置和身上钥匙可以开的门记录下来,然后有一个地方就是,一个地点可能会有多把钥匙,这个要想到。然后把可以开那些门用二进制的1表示就好了,应为最多也就10个门。


#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int nodes=15;
int n,m,p;
bool wall[nodes][nodes][nodes][nodes];
int door[nodes][nodes][nodes][nodes];
int key[nodes][nodes];
bool vis[1<<12][nodes][nodes];
int dir[4][2]={1,0,0,1,0,-1,-1,0};
struct node
{
    int x,y;
    int sta;
    int tim;
};
void init()
{
    memset(wall,false,sizeof(wall));
    memset(door,0,sizeof(door));
    memset(key,0,sizeof(key));
}
void bfs()
{
    memset(vis,false,sizeof(vis));
    node head,nxt;
    queue<node>q;
    while(!q.empty()) q.pop();
    head.x=1;head.y=1;head.sta=0;head.tim=0;
    if(key[1][1])
    {
        head.sta|=key[1][1];
    }
    q.push(head);
    vis[head.sta][1][1]=true;
    while(!q.empty())
    {
        head=q.front();
        q.pop();
        if(head.x==n&&head.y==m)
        {
            printf("%d\n",head.tim);
            return;
        }
        for(int i=0;i<4;i++)
        {
            nxt.x=head.x+dir[i][0];
            nxt.y=head.y+dir[i][1];
            nxt.tim=head.tim+1;
            nxt.sta=head.sta;
            if(wall[head.x][head.y][nxt.x][nxt.y]) continue;
            if(nxt.x<1||nxt.x>n||nxt.y<1||nxt.y>m) continue;
            int dn=door[head.x][head.y][nxt.x][nxt.y];
            if(dn)
            {
                if(!(1<<(dn-1)&nxt.sta)) continue;
            }
            if(key[nxt.x][nxt.y])
            {
                nxt.sta|=key[nxt.x][nxt.y];
            }
            if(!vis[nxt.sta][nxt.x][nxt.y])
            {
                vis[nxt.sta][nxt.x][nxt.y]=true;
                q.push(nxt);
            }
        }
    }
    printf("-1\n");
    return;
}
int main()
{
    while(~scanf("%d%d%d",&n,&m,&p))
    {
        init();
        int K;
        scanf("%d",&K);
        for(int i=1;i<=K;i++)
        {
            int x1,y1,x2,y2,g;
            scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&g);
            if(!g) wall[x1][y1][x2][y2]=wall[x2][y2][x1][y1]=true;
            else door[x1][y1][x2][y2]=door[x2][y2][x1][y1]=g;
        }
        int S;
        scanf("%d",&S);
        for(int i=1;i<=S;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            key[x][y]|=1<<(z-1);
        }
        bfs();
    }
    return 0;
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值