首页 > 代码库 > hdu-1429 胜利大逃亡(续)
hdu-1429 胜利大逃亡(续)
http://acm.hdu.edu.cn/showproblem.php?pid=1429
第一次接触搜索+状态压缩 看了大神的题解 勉强把题目弄懂了。
用二进制来表示手头的钥匙有哪些,100表示有第三把钥匙,111表示有第三、二、一把,搜索下一点时,如果该点为钥匙点,则可采用|运算来
模拟拾取,显然0001 | 1000 = 1001,同理,当为相应的门时采用&运算来模拟开启,例如1101 & 0001 = 0001(即可以打开‘A‘门)
#include<cstdio> #include<cstring> #include<queue> using namespace std; int n,m,t,ans; char map[25][25]; int vis[25][25][1030];//标记数组 int dir[4][2]={-1,0,1,0,0,1,0,-1}; //四个方向 struct point { int x,y,step,key; }; point s; int check(int x,int y)//检查 { if(s.x>=0&&s.x<n&&s.y>=0&&s.y<m) return 1; return 0; } void bfs() { point tp; queue<point>q; vis[s.x][s.y][s.key]=1; for(q.push(s);!q.empty();q.pop()) { tp=q.front(); for(int k=0;k<4;k++) { s=tp; //注意这里要先把tp赋值给s,即先把上次搜索到的保存下来,再去扩展。 s.x=tp.x+dir[k][0]; s.y=tp.y+dir[k][1]; if(check(s.x,s.y)&&map[s.x][s.y]!='*'&&!vis[s.x][s.y][s.key]) { if(map[s.x][s.y]=='.'||map[s.x][s.y]=='@') { vis[s.x][s.y][s.key]=1; s.step++; q.push(s); } if(map[s.x][s.y]=='^') { if(s.step+1<t) ans=s.step+1; return; } if(map[s.x][s.y]>='A'&&map[s.x][s.y]<='J') {//a<<2表示将a是二进制左移2位(相当于*4),这里用来表示钥匙eg:A-A=0;1<<0,就是0000 0001就是第一把钥匙了。 //同理当g[s.x][s.y]='B'时,就是1<<2,就是0000 0010,表示第二把钥匙; int key=1<<(map[s.x][s.y]-'A');//按位于运算,当有对应的钥匙时,等式成立;才能打开门 if(s.key&key) { vis[s.x][s.y][s.key]=1; s.step+=1; q.push(s); } } if(map[s.x][s.y]>='a'&&map[s.x][s.y]<='j') { //按位或运算,吸收钥匙; int key=1<<(map[s.x][s.y]-'a'); if(!vis[s.x][s.y][s.key|key]) { vis[s.x][s.y][s.key|key]=1; s.step+=1; s.key=s.key|key; q.push(s); } } } } } } int main() { while(scanf("%d%d%d",&n,&m,&t)!=EOF) { memset(vis,0,sizeof(vis)); ans=-1; for(int i=0;i<n;i++) { scanf("%s",map[i]); for(int j=0;j<m;j++) { if(map[i][j]=='@') { s.x=i; s.y=j; s.key=0; s.step=0; } } } bfs(); printf("%d\n",ans); } return 0; }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。