hdu1429推箱子

题意:从“@”走到'^',问最短步数,所以就是用bfs。途中会遇见A——J和a——j、,分别代表门和钥匙。所以就要用拥有钥匙的状态和没有钥匙的状态,我们用状态压缩来解决。

思路:

首先不知道位运算的需要先学习一下位运算,我的博客里还没有关于位运算的知识点,知识学的不好,不敢随便卖弄,等我深造好了,就出一个。给一个连接吧,我是在上面学的

。http://baike.sogou.com/v576970.htm。

这道题没有想象的那么难,不过是用二进制表示状态,其余的和正常的bfs是一个样子的。

最关键的地方到了哦,就是怎么用二进制表示状态。

1、用到的几个二进制数都是2的n次方,比如1,2,4,8,16.。。。。。这些数的二进制都是一个1和(n-1)个0;

1——1;

2——10;

4——100;

8——1000;

。。。。。。。。

2、需要用的位运算有:<<和‘|’;用法在上面的地址了里,好好研究一下就会懂;

3、遇见a——j时把钥匙吸收进去,很简单。

遇见A——J时随便定义一个变量,把门的号吸收进去,和钥匙的作对比,如果相等的话,则可以打开门。否则不能打开门。

原理:比如有c的钥匙了,那么二进制中第三位就要有一个1,不管途中吸没吸收其他的钥匙,第三位的一是不会变的,那么门上的第三位,吸收进去1还是1,所以二进制是不会改变的,二进制与十进制是一一对应的,那么十进制就不会改变

至于代码,我认为要是从来没有做过这种题的话,就直接看看吧,看一遍就会了,在找别的题来练练,如果做过别的题的话,这道题并不算难了。

代码如下:

#include<stdio.h>
#include<string.h>
#include<queue>
#include<iostream>
using namespace std;
struct node
{
int x,y;
int step;
int num_key;
};
int dir[4][2]={1,0,0,1,-1,0,0,-1};
int n,m,time;
int x1,x2,y1,y2;
char map[21][21];
int mark[21][21][2000];
bool can_go(int xx,int yy)
{
if(xx>=0&&yy>=0&&xx<n&&yy<m&&map[xx][yy]!='*') return 1;
return 0;
}
int bfs()
{
queue<node>q;
node first,last;
first.x=x1;
first.y=y1;
first.step=0;
first.num_key=0;
mark[first.x][first.y][first.num_key]=1;
q.push(first);
while(!q.empty())
{
first=q.front();
q.pop();
if(first.x==x2&&first.y==y2&&first.step<time)
{
return first.step;
}
for(int i=0;i<4;i++)
{
last.x=first.x+dir[i][0];
last.y=first.y+dir[i][1];
last.step=first.step+1;
last.num_key=first.num_key;
if(can_go(last.x,last.y))
{
if(mark[last.x][last.y][last.num_key]==1) continue;
if(map[last.x][last.y]>='A'&&map[last.x][last.y]<='J')
{
int key;
key=last.num_key|(1<<(map[last.x][last.y]-'A'));//吧门号吸收进去,看看会不会对应位置的二进制数造成影响,从而判断有没有打开这扇门的钥匙。
if(key!=last.num_key) continue;
}
if(map[last.x][last.y]>='a'&&map[last.x][last.y]<='j')
{
last.num_key=last.num_key|(1<<(map[last.x][last.y]-'a'));//吸收钥匙,就是把钥匙编号装换为二进制,加入到队列中。
}
mark[last.x][last.y][last.num_key]=1;
q.push(last);
}
}
}
return -1;
}
int main()
{
int can;
while(scanf("%d%d%d",&n,&m,&time)!=EOF)
{
memset(map,'\0',sizeof(map));
memset(mark,0,sizeof(mark));
for(int i=0;i<n;i++)
{
scanf("%s",&map[i]);
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(map[i][j]=='@')
{
x1=i;y1=j;
}
else if(map[i][j]=='^')
{
x2=i;y2=j;
}
}
}
can=bfs();
printf("%d\n",can);
}
return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值