HDU1885 Key Task(BFS状态压缩)

题目链接

  • 题意:
    输入R×C大小的地图,其中’*‘表示起点位置,’#‘表示不可以通过,’.'表示可以通过,‘B’,‘Y’,‘R’,'G’分别表示蓝、黄、红、绿门,‘b’,‘y’,‘r’,'g’分别表示蓝、黄、红、绿门的钥匙,'X’表示出口,注意输入数据可能含有零个或多个出口,可能含有多个相同颜色的门或钥匙,可能存在无匹配的钥匙\门的情况,要求计算从起点到终点的最短路径。

  • 思路:
    由于可能出现同一结点在不同时间可以被多次访问、多个相同颜色的钥匙、钥匙\门不匹配的情况,所以不能仅仅通过记录钥匙的数量来标记结点,而应记录每个结点钥匙的持有情况(共2^4=16种)。为了操作方便与减少空间消耗,进行状态压缩,用一个二进制数来表示钥匙的持有状况,故为标记数组增加一维用来记录结点的钥匙持有情况即可完成标记。

  • 二进制数操作回顾:
int GetBit(char c,int i)//取c的第i位 
{
	return (c>>i)&1;
}
void SetBit(char &c,int i,int v)//设置c的第i位为v(0/1)
{
	if(v)
		c|=(1<<i);
	else
		c&=~(1<<i);
}
void Flip(char &c,int i)//将c的第i位取反 
{
	c^=(1<<i);
}
  • 代码实现:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <cmath>
#include <map>
using namespace std;

map<char,int> m;
int d[4][2]={{1,0},{-1,0},{0,-1},{0,1}};
char color[]={'B','Y','R','G'};
char colorkeys[]={'b','y','r','g'};
char maze[110][110];
bool reach[110][110][20];
int r,c;

struct s{
	int x;
	int y;
	int steps;
	int keys;
	s(){}
	s(int xx,int yy,int ss,int k):x(xx),y(yy),steps(ss),keys(k){}
};

bool Range(int x,int y,int &k){
	if(x<0||y<0||x>=r||y>=c||maze[x][y]=='#')
		return false;
	if(islower(maze[x][y])){
		int i=m[maze[x][y]];
		k=k|(1<<i);
		if(!reach[x][y][k])
			return true;
	}
	else if(isupper(maze[x][y])&&maze[x][y]!='X'){
		int i=m[maze[x][y]];
		int j=k&(1<<i);
		if(j&&!reach[x][y][k])
				return true;
	}
	else if(!reach[x][y][k])
		return true;
	return false;
}

int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	m['B']=0;m['Y']=1;m['R']=2;m['G']=3;
	m['b']=0;m['y']=1;m['r']=2;m['g']=3;
	while(cin>>r>>c){
		if(r==0&&c==0)
			break;
		s s0;
		memset(reach,0,sizeof(reach));
		bool flag=false;
		for(int i=0;i<r;i++){
			for(int j=0;j<c;j++){
				cin>>maze[i][j];
				if(maze[i][j]=='X')
					flag=true;
				if(maze[i][j]=='*'){
					s0=s(i,j,0,0);
				}
			}
		}
		if(!flag){
			cout<<"The poor student is trapped!"<<endl;
			continue;
		}
		queue<s> q;
		q.push(s0);
		reach[s0.x][s0.y][0]=1;
		bool f=false;
		while(!q.empty()){
			s t=q.front();
			q.pop();
			if(maze[t.x][t.y]=='X'){
				cout<<"Escape possible in "<<t.steps<<" steps."<<endl;
				f=true;
				break;
			}
			for(int i=0;i<4;i++){
				int kk=t.keys;
				int dx=t.x+d[i][0];
				int dy=t.y+d[i][1];
				if(Range(dx,dy,kk)){
					reach[dx][dy][kk]=1;
					q.push(s(dx,dy,t.steps+1,kk));
				}	
			}
		}
		if(!f)
			cout<<"The poor student is trapped!"<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值