HDU_1429——胜利大逃亡续,十位二进制状态压缩,状态判重
Problem Description
Ignatius再次被魔王抓走了(搞不懂他咋这么讨魔王喜欢)……
这次魔王汲取了上次的教训,把Ignatius关在一个n*m的地牢里,并在地牢的某些地方安装了带锁的门,钥匙藏在地牢另外的某些地方。刚开始Ignatius被关在(sx,sy)的位置,离开地牢的门在(ex,ey)的位置。Ignatius每分钟只能从一个坐标走到相邻四个坐标中的其中一个。魔王每t分钟回地牢视察一次,若发现Ignatius不在原位置便把他拎回去。经过若干次的尝试,Ignatius已画出整个地牢的地图。现在请你帮他计算能否再次成功逃亡。只要在魔王下次视察之前走到出口就算离开地牢,如果魔王回来的时候刚好走到出口或还未到出口都算逃亡失败。
这次魔王汲取了上次的教训,把Ignatius关在一个n*m的地牢里,并在地牢的某些地方安装了带锁的门,钥匙藏在地牢另外的某些地方。刚开始Ignatius被关在(sx,sy)的位置,离开地牢的门在(ex,ey)的位置。Ignatius每分钟只能从一个坐标走到相邻四个坐标中的其中一个。魔王每t分钟回地牢视察一次,若发现Ignatius不在原位置便把他拎回去。经过若干次的尝试,Ignatius已画出整个地牢的地图。现在请你帮他计算能否再次成功逃亡。只要在魔王下次视察之前走到出口就算离开地牢,如果魔王回来的时候刚好走到出口或还未到出口都算逃亡失败。
Input
每组测试数据的第一行有三个整数n,m,t(2<=n,m<=20,t>0)。接下来的n行m列为地牢的地图,其中包括:
. 代表路 * 代表墙 @ 代表Ignatius的起始位置 ^ 代表地牢的出口 A-J 代表带锁的门,对应的钥匙分别为a-j a-j 代表钥匙,对应的门分别为A-J
每组测试数据之间有一个空行。
. 代表路 * 代表墙 @ 代表Ignatius的起始位置 ^ 代表地牢的出口 A-J 代表带锁的门,对应的钥匙分别为a-j a-j 代表钥匙,对应的门分别为A-J
每组测试数据之间有一个空行。
Output
针对每组测试数据,如果可以成功逃亡,请输出需要多少分钟才能离开,如果不能则输出-1。
Sample Input
4 5 17
@A.B.
a*.*.
*..*^
c..b*
4 5 16
@A.B.
a*.*.
*..*^
c..b*
Sample Output
16
-1
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 using namespace std; 5 6 const int dir[4][2] = {0,1,0,-1,1,0,-1,0}; 7 int n, m, t; 8 char map[25][25]; 9 10 struct node 11 { 12 int x, y, key; //key的每一个二进制位代表一种钥匙 13 int step; 14 bool out(void) 15 { 16 if(map[x][y] == '^') 17 { 18 return true; 19 } 20 return false; 21 } 22 bool check(void) 23 { 24 if(x>=0 && x<n && y>=0 && y<m) 25 { 26 if(map[x][y] != '*') 27 { 28 return true; 29 } 30 } 31 return false; 32 } 33 bool is_key(void) 34 { 35 if(map[x][y]>='a' && map[x][y]<='j') 36 { 37 return true; 38 } 39 return false; 40 } 41 bool is_door(void) 42 { 43 if(map[x][y]>='A' && map[x][y]<='J') 44 { 45 return true; 46 } 47 return false; 48 } 49 }u,v; 50 51 //标记已搜索过的状态,根据主角手中拿到的不同的钥匙及其所在位置来区分不同的状态, 52 //就像推箱子中,用所达某一位置时人物面对的方向来标记某一个状态 53 int mark[25][25][1024]; //数组太大不能在函数中定义 54 int BFS(void) 55 { 56 memset(mark,0,sizeof(mark)); 57 queue<node>que; 58 que.push(u); 59 60 while(!que.empty()) 61 { 62 u = que.front(); 63 que.pop(); 64 65 if(u.out()) //逃出 66 { 67 return (t - u.step); 68 } 69 for(int i=0; i<4; i++) //枚举方向 70 { 71 v.x = u.x + dir[i][0]; 72 v.y = u.y + dir[i][1]; 73 v.step = u.step - 1; 74 v.key = u.key; 75 76 if(v.step == 0) //逃不出 77 { 78 continue; 79 } 80 81 if(v.check() && !mark[v.x][v.y][v.key]) //检查越界,撞墙,标记重复 82 { 83 if(v.is_key()) //走到钥匙 84 { 85 v.key |= 1 << (map[v.x][v.y] - 'a'); //把钥匙带走,对应二进制标志位置1 86 } 87 else if(v.is_door()) //走到门 88 { 89 if((v.key & (1 << (map[v.x][v.y] - 'A'))) == 0) //身上的钥匙不能开这个门 90 { 91 continue; 92 } 93 } 94 mark[v.x][v.y][v.key] = 1; 95 que.push(v); 96 } 97 } 98 } 99 return -1; 100 } 101 102 int main() 103 { 104 while(~scanf("%d%d%d", &n,&m,&t)) 105 { 106 for(int i=0; i<n; i++) 107 { 108 scanf("%s", map[i]); 109 for(int j=0; j<m; j++) 110 { 111 if(map[i][j] == '@') 112 { 113 u.x = i; 114 u.y = j; 115 u.key = 0; 116 u.step = t; 117 } 118 } 119 } 120 printf("%d\n",BFS()); 121 } 122 return 0; 123 }
——现在的努力是为了小时候吹过的牛B!!