hdu 5091 Maze (bfs+状态压缩)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5094

题意:给定一张格子图,(1,1)为起点,(n,m)为终点,每个节点和它相邻的节点会存在墙和门,其中门有好多种,当到达这个位置的时候如果你没有这个门的钥匙的话,就不能穿过这个门,每种门的钥匙分散在图上的个个地方,问从起点到终点的最短距离。

思路:大bfs,加一维来表示到达每个地方时所获钥匙的状态,dp[x][y][k]表示到达图上x,y这个地方时所获钥匙状态为k时的最短路径,对于每个位置就向四个方向搜救行了,状态转移时要考虑墙和门。

像这样的题目思路大家都知道,就是写起来的时候要注意,每个地方都要思考用尽量好的姿势来做,具体细节看代码~


code:

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#define INF 1000000007
using namespace std;

const int maxn=55;
const int maxe=100000;

int dp[maxn][maxn][1<<11];

//door 为门数组 -1 表示没有障碍物 0 表示存在墙 1~。。 表示存在哪种门 数组的最后一维用来表示方向
//key为钥匙数组 用二进制来表示每个位置都放了那几种钥匙
int door[maxn][maxn][4];
int key[maxn][maxn];
int n,m,q;

int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};

struct node
{
	int x,y,st;
	node(){};
	node(int x,int y,int st): x(x),y(y),st(st){}
};

queue<node> qq;

void bfs(int x,int y)
{
	memset(dp,-1,sizeof(dp));
	qq.push(node(x,y,0));
	dp[x][y][0]=0;
	while(qq.size()){
		node v=qq.front(); qq.pop();
		for(int i=0;i<4;i++){
			int mx=v.x+dx[i],my=v.y+dy[i],ms=v.st;
			if(mx<1||mx>n||my<1||my>m) continue;
			if(door[v.x][v.y][i]==0) continue;
			if(door[v.x][v.y][i]==-1||(1<<(door[v.x][v.y][i]-1)&v.st)){
                ms|=key[mx][my];
                if(dp[mx][my][ms]==-1||dp[mx][my][ms]>dp[v.x][v.y][v.st]+1){
                    dp[mx][my][ms]=dp[v.x][v.y][v.st]+1;
                    qq.push(node(mx,my,ms));
                }
			}
		}
	}
	int res=INF;
	for(int i=0;i<(1<<q);i++) if(dp[n][m][i]!=-1) res=min(res,dp[n][m][i]);
	if(res==INF) printf("-1\n");
	else printf("%d\n",res);
}
int main()
{
	int kk;
	int x1,x2,y1,y2,g;
	while(scanf("%d%d%d",&n,&m,&q)!=EOF){
		memset(door,-1,sizeof(door));
		memset(key,0,sizeof(key));
		scanf("%d",&kk);
		while(kk--){
			scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&g);
			int i;
			for(i=0;i<4;i++){
				int mx=x1+dx[i],my=y1+dy[i];
				if(mx==x2&&my==y2) break;
			}
			//注意建立双向门
			door[x1][y1][i]=g;
			door[x2][y2][i^1]=g;
		}
		scanf("%d",&kk);
		while(kk--){
			scanf("%d%d%d",&x1,&y1,&g);
			key[x1][y1]|=1<<(g-1);
		}
		bfs(1,1);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值