题面:

Maze

题目中文大意:
这个故事发生在“星际迷航”的背景下。

“星际争霸”的副队长史波克落入克林贡的诡计中,被关押在他们的母亲星球Qo’noS上。

企业的上尉詹姆斯·T·柯克(James T. Kirk)不得不乘宇宙飞船去救他的副手。幸运的是,他偷走了史波克所在的迷宫地图。

迷宫是一个矩形,它有n行垂直和m列水平,换句话说,它被分为n * m个位置。有序对(行号,列号)表示迷宫中的位置。柯克从当前位置移动到下一个花费1秒。而且他只有在以下情况下才能移动到下一个位置:

下一个位置与当前柯克的位置相邻(上下或左右)(4个方向)
开着的门是可以通行的,但锁着的门不是。
柯克不能通过一堵墙

有几种门是默认锁定的。钥匙只能打开相同类型的门。柯克必须在打开相应的门之前拿到钥匙,这样很浪费时间。

柯克的初始位置是(1,1),而史波克位于(n,m)的位置。你的任务是帮助Kirk尽快找到史波克。
Input
输入包含很多测试样例。

每个测试样例由几行组成。第一行中有三个整数,分别代表n,m和p (1<= n, m <=50, 0<= p <=10).
第二行只列出一个整数k,表示门和墙的总数(0<= k <=500).

在下面的k行中有5个整数,表示 i1, y i1, x i2, y i2, g i; 当g i >=1,表示在位置 (x i1, y i1) 和 (x i2, y i2)之间存在类型gi的门;当g i = 0,说明 (x i1, y i1)和 (x i2, y i2),之间存在一堵墙 ( | x i1 - x i2 | + | y i1 - y i2 |=1, 0<= g i <=p )

下面的行是一个整数S,表示迷宫中的钥匙的总数。(0<= S <=50).

在下面的S行中有三个整数,分别表示x i1, y i1和q i这意味着类型为qi的钥匙位于位置 i (x i1, y i1), (1<= q i<=p).

Output
输出Kirk可能达到史波克的可能最小的秒数。

如果没有可能的计划,输出-1。
Sample Input
4 4 9
9
1 2 1 3 2
1 2 2 2 0
2 1 2 2 0
2 1 3 1 0
2 3 3 3 0
2 4 3 4 1
3 2 3 3 0
3 3 4 3 0
4 3 4 4 0
2
2 1 2
4 2 1
Sample Output
14

分析:

此题应使用广度优先搜索(BFS)
状态压缩:有10种钥匙,那么我们用10位二进制来存储钥匙串(即一个int整型变量),第i-1位是1表示有第i种钥匙,为0则没有钥匙
用位运算来判断是否能通过门(这些操作很常用,应牢记

  1. 将第i种钥匙加入钥匙串key
    代码:key|=(1<<(i-1))
    例:key=0010 ,i=4,1<<(i-1)=1000,0010|1000=1010

  2. 拿着钥匙串key,是否能通过第i种门
    代码:if(key&(1<<(i-1)==0) continue
    例:(没拿到第5种钥匙,想通过第5种门)key=01101,i=5,1<<(i-1)=10000,00101|10000=0,通不过,continue
    (拿到第4种钥匙,想通过第4种门)key=01101,i=4,1<<(i-1)=01000,00101|10000=01000,可通过

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 56
#define maxqu 50*50*(1<<11)+10
using namespace std;
int n,m,p,k,s;
struct node{
int x;
int y;
int step;
int key;//存储钥匙
};
node now,nex;
node queue[maxqu];
int door[maxn][maxn][maxn][maxn];//邻接矩阵存门
int keys[maxn][maxn];//二维数组存储每一个点的钥匙
int used[maxn][maxn][2055];//标志是否走过
const int walkx[4]={1,-1,0,0},walky[4]={0,0,1,-1};
int fread(){//快速输入
int x=0;
char c=getchar();
int sign=1;
while(c<'0'||c>'9') {
if(c=='-') sign=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
return x*sign;
}
bool judge(int x1,int y1,int x2,int y2){
if(door[now.x][now.y][nex.x][nex.y]==0) return false;//有墙
if(x2>=1&&x2<=n&&y2>=1&&y2<=m) return true;
else return false;
}
int bfs(){
int head=0,tail=0;
int tmp;
queue[0].x=1;
queue[0].y=1;
queue[0].step=0;
queue[0].key|=keys[1][1];//起点有钥匙的特判
memset(used,0,sizeof(used));
used[1][1][queue[0].key]=1;
do{
now=queue[head];
if(now.x==n&&now.y==m) return now.step;
for(int i=0;i<4;i++){
nex.x=now.x+walkx[i];
nex.y=now.y+walky[i];
nex.key=now.key;
nex.step=now.step;
if(judge(now.x,now.y,nex.x,nex.y)){
if(door[now.x][now.y][nex.x][nex.y]>0){//开门
tmp=door[now.x][now.y][nex.x][nex.y]-1;
if((nex.key&(1<<tmp))==0) continue;
}
if(keys[nex.x][nex.y]>0){//拿钥匙
nex.key|=keys[nex.x][nex.y];
}
if(used[nex.x][nex.y][nex.key]==1) continue;
used[nex.x][nex.y][nex.key]=1;
tail++;
queue[tail].x=nex.x;
queue[tail].y=nex.y;
queue[tail].key=nex.key;
queue[tail].step=nex.step+1;
}
}
head++;
}while(head<=tail);
return -1;
}
int main(){
// freopen("data.txt","r",stdin);
int x1,y1,x2,y2,v;
while(cin>>n>>m>>p){
memset(door,-1,sizeof(door));
memset(keys,0,sizeof(keys));
k=fread();
for(int i=1;i<=k;i++){
x1=fread();
y1=fread();
x2=fread();
y2=fread();
v=fread();
door[x1][y1][x2][y2]=v;//>0门,=0墙,-1无
door[x2][y2][x1][y1]=v;
}
cin>>s;
for(int i=1;i<=s;i++){
x1=fread();
y1=fread();
v=fread();
keys[x1][y1]|=(1<<(v-1));//预处理钥匙,注意一个位置有多个钥匙的情况
}
cout<<bfs()<<endl;
}
}

HDU 5094 题解(状压BFS)的更多相关文章

  1. 拯救大兵瑞恩 HDU - 4845(状压bfs || 分层最短路)

    1.状压bfs 这个状压体现在key上  我i们用把key状压一下  就能记录到一个点时 已经拥有的key的种类 ban[x1][y1][x2][y1]记录两个点之间的状态 是门 还是墙 还是啥都没有 ...

  2. HDU 4012 Paint on a Wall(状压+bfs)

    Paint on a Wall Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) ...

  3. HDU Stealing Harry Potter's Precious(状压BFS)

    状压BFS 注意在用二维字符数组时,要把空格.换行处理好. #include<stdio.h> #include<algorithm> #include<string.h ...

  4. POJ 1324 Holedox Moving (状压BFS)

    POJ 1324 Holedox Moving (状压BFS) Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 18091 Acc ...

  5. P2622 关灯问题II(状压bfs)

    P2622 关灯问题II 题目描述 现有n盏灯,以及m个按钮.每个按钮可以同时控制这n盏灯——按下了第i个按钮,对于所有的灯都有一个效果.按下i按钮对于第j盏灯,是下面3中效果之一:如果a[i][j] ...

  6. 状压BFS

    ​题意:1个机器人找几个垃圾,求出最短路径. 状压BFS,这道题不能用普通BFS二维vis标记数组去标记走过的路径,因为这题是可以往回走的,而且你也不能只记录垃圾的数量就可以了,因为它有可能重复走同一 ...

  7. hdu 5094 状压bfs+深坑

    http://acm.hdu.edu.cn/showproblem.php?pid=5094 给出n*m矩阵 给出k个障碍,两坐标之间存在墙或门,门最多10种,状压可搞 给出s个钥匙位置及编号,相应的 ...

  8. HDU 4284Travel(状压DP)

    HDU 4284    Travel 有N个城市,M条边和H个这个人(PP)必须要去的城市,在每个城市里他都必须要“打工”,打工需要花费Di,可以挣到Ci,每条边有一个花费,现在求PP可不可以从起点1 ...

  9. [HNOI2006]最短母串问题——AC自动机+状压+bfs环形处理

    Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. 32MB Input 第一行是一个正整数n(n< ...

  10. 洛谷P4011 孤岛营救问题(状压+BFS)

    传送门 和网络流有半毛钱关系么…… 可以发现$n,m,p$都特别小,那么考虑状压,每一个状态表示位置以及钥匙的拥有情况,然后每次因为只能走一步,所以可以用bfs求出最优解 然后是某大佬说的注意点:每个 ...

随机推荐

  1. Azure IoT 技术研究系列3

    上篇博文中我们将模拟设备注册到Azure IoT Hub中:我们得到了设备的唯一标识. Azure IoT 技术研究系列2-设备注册到Azure IoT Hub 本文中我们继续深入研究,设备到云.云到 ...

  2. 岭回归、lasso

    参考:https://blog.csdn.net/Byron309/article/details/77716127     ----    https://blog.csdn.net/xbinwor ...

  3. __new__与__init__的区别

    __new__  : 控制对象的实例化过程 , 在__init__方法之前调用 __init__ : 对象实例化对象进行属性设置 class User: def __new__(cls, *args, ...

  4. BZOJ 3043: IncDec Sequence 差分 + 思维

    Code: #include <bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) ...

  5. SpringCloud 教程 (四) docker部署spring cloud项目

    一.docker简介 Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的.可移植的.自给自足的容器.开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机). ...

  6. 微信小程序支付 java

    原文:https://blog.csdn.net/zhourenfei17/article/details/77765585 话不多说,直接开撸. 支付流程步骤: 1)首先调用wx.login方法获取 ...

  7. 170906-MyBatis续

    ===============================================Dynamic SQL========================================== ...

  8. MySQL Schedule Event

    建立事件历史日志表-- 用于查看事件执行时间等信息create table t_event_history  (     dbname  varchar(128) not null default ' ...

  9. C++新旧类型转换小记

    旧式类型转换可应对一切转换,不管合不合理,有没有风险,你让我转我就转给你,后果自负. 新式类型转换比较安全,主要体现在父子类之间的运行时转换 dynamic_cast上,若转换失败则返回空指针,而旧式 ...

  10. linux 杀掉僵尸进程 (zombie process, defunct)

    本文说明为什么会出现僵尸进程 (zombie process, defunct),以及如何杀掉僵尸进程 1. 为什么有僵尸进程 僵尸进程出现在父进程没有回收子进程的 PCB 的时候,这个时候子进程已经 ...