HDU 5094 题解(状压BFS)
题面:
题目中文大意:
这个故事发生在“星际迷航”的背景下。
“星际争霸”的副队长史波克落入克林贡的诡计中,被关押在他们的母亲星球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则没有钥匙
用位运算来判断是否能通过门(这些操作很常用,应牢记)
将第i种钥匙加入钥匙串key
代码:key|=(1<<(i-1))
例:key=0010 ,i=4,1<<(i-1)=1000,0010|1000=1010拿着钥匙串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)的更多相关文章
- 拯救大兵瑞恩 HDU - 4845(状压bfs || 分层最短路)
1.状压bfs 这个状压体现在key上 我i们用把key状压一下 就能记录到一个点时 已经拥有的key的种类 ban[x1][y1][x2][y1]记录两个点之间的状态 是门 还是墙 还是啥都没有 ...
- 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) ...
- HDU Stealing Harry Potter's Precious(状压BFS)
状压BFS 注意在用二维字符数组时,要把空格.换行处理好. #include<stdio.h> #include<algorithm> #include<string.h ...
- POJ 1324 Holedox Moving (状压BFS)
POJ 1324 Holedox Moving (状压BFS) Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 18091 Acc ...
- P2622 关灯问题II(状压bfs)
P2622 关灯问题II 题目描述 现有n盏灯,以及m个按钮.每个按钮可以同时控制这n盏灯——按下了第i个按钮,对于所有的灯都有一个效果.按下i按钮对于第j盏灯,是下面3中效果之一:如果a[i][j] ...
- 状压BFS
题意:1个机器人找几个垃圾,求出最短路径. 状压BFS,这道题不能用普通BFS二维vis标记数组去标记走过的路径,因为这题是可以往回走的,而且你也不能只记录垃圾的数量就可以了,因为它有可能重复走同一 ...
- hdu 5094 状压bfs+深坑
http://acm.hdu.edu.cn/showproblem.php?pid=5094 给出n*m矩阵 给出k个障碍,两坐标之间存在墙或门,门最多10种,状压可搞 给出s个钥匙位置及编号,相应的 ...
- HDU 4284Travel(状压DP)
HDU 4284 Travel 有N个城市,M条边和H个这个人(PP)必须要去的城市,在每个城市里他都必须要“打工”,打工需要花费Di,可以挣到Ci,每条边有一个花费,现在求PP可不可以从起点1 ...
- [HNOI2006]最短母串问题——AC自动机+状压+bfs环形处理
Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. 32MB Input 第一行是一个正整数n(n< ...
- 洛谷P4011 孤岛营救问题(状压+BFS)
传送门 和网络流有半毛钱关系么…… 可以发现$n,m,p$都特别小,那么考虑状压,每一个状态表示位置以及钥匙的拥有情况,然后每次因为只能走一步,所以可以用bfs求出最优解 然后是某大佬说的注意点:每个 ...
随机推荐
- 自定义指令 限制input 的输入位数
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8 ...
- noip考前抱佛脚 数论小总结
exCRT 求解韩信点兵问题,常见的就是合并不同\(mod\). 先mo一发高神的板子 for(R i=2;i<=n;++i){ ll Y1,Yi,lcm=Lcm(p[i],p[1]); exg ...
- ZROI 19.07.28 组合计数/lb
T1 题意:\(n\)个变量,\(0 \leq x_i \leq c_i\),求\(\sum x_i = A\)方案数.\(n \leq 32\). Sol: \(n \leq 10\)的时候容斥很水 ...
- linux下实现web数据同步的四种方式(性能比较)
实现web数据同步的四种方式 ======================================= 1.nfs实现web数据共享2.rsync +inotify实现web数据同步3.rsyn ...
- 【BZOJ3601】一个人的数论
题目链接 题意简述 求小于 n 且与 n 互质的数的 k 次方之和. Sol 要求的东西: \[\sum_{i=1}^n i^k [gcd(i,n)=1]\] 枚举 gcd 上个莫比乌斯函数: \[\ ...
- 对Moment.js的研究
创建npm install moment --save-dev 日期格式化 moment().format('MMMM Do YYYY, h:mm:ss a'); // 六月 4日 2019, 6:2 ...
- 简单说说JavaBean的使用
一:JavaBean定义 JavaBean是一种可重复使用.跨平台的软件组件.JavaBean可分为两种:一种是有用户界面(UI,User Interface)的JavaBean,例如中的那些可视化图 ...
- C中的system函数
windows操作系统下system () 函数详解(主要是在C语言中的应用) 函数名: system 功 能: 发出一个DOS命令 用 法: int system(char *command); s ...
- [CF1093E]Intersection of Permutations:树套树+pbds
分析 裸的二维数点,博主用树状数组套平衡树写的,顺便pbds真好用. Update on 2018/12/20:再解释一下为什么是二维数点,第一维是\(la \leq i \leq ra\),第二维是 ...
- Java 线程状态有哪些?
线程状态有 5 种,新建,就绪,运行,阻塞,死亡.关系图如下: 1. 线程 start 方法执行后,并不表示该线程运行了,而是进入就绪状态,意思是随时准备运行,但是真正何时运行,是由操作系统决定的,代 ...