oj题目:猛戳~~
胜利大逃亡(续)
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 -1const int inf = 100000; int dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}}; int n,m,t; int dp[21][21][1<<10];//dp[i][j][k]在jail[i][j]处,获得钥匙状态为k时的最少步数 char jail[21][21];//地牢地形 struct Node { int x; int y; int key; int step; Node(){} Node(int a,int b,int c,int d):x(a),y(b),key(c),step(d){} friend bool operator < (const Node & A , const Node & B)//步数最少的出现在堆顶 { return A.step > B.step; } }; Node s;//起始位置 bool cango(int x,int y) { return 1 <= x && x <= n && 1 <= y && y <= m; } int DP() { priority_queue<Node> que;//加快搜索速度 que.push(s); while(!que.empty()) { Node now = que.top(); que.pop(); int nowstep = now.step; int nowkey = now.key; if(nowstep >= t)//已经被发现了,还没有逃出,不用再往下搜索了 continue; if(jail[now.x][now.y] == '^')//没有被发现,而且到了出口,则成功 return nowstep; for(int i = 0;i < 4;i++)//四个方向 { int x = now.x + dir[i][0]; int y = now.y + dir[i][1]; if(!cango(x,y)||jail[x][y] == '*')//此处超出了地牢的范围或者是墙,跳过,不往下搜索。 continue; if('a' <= jail[x][y] && jail[x][y] <= 'j')//如果此处是钥匙 { int key = now.key | (1<<(jail[x][y] - 'a'));//捡起钥匙 if(dp[x][y][key] > nowstep + 1)//更新步数,保留最少 { dp[x][y][key] = nowstep + 1; que.push(Node(x , y , key , nowstep + 1));//加入堆 } } else if('A' <= jail[x][y] && jail[x][y] <= 'J')//如果是门 { if(nowkey&(1 << jail[x][y] - 'A')&&dp[x][y][nowkey] > nowstep + 1) {//如果已经获得此门的钥匙且此状态下去步数较少,则更新 dp[x][y][nowkey] = nowstep + 1; que.push(Node(x , y , nowkey , nowstep + 1)); } } else { if(dp[x][y][nowkey] > nowstep + 1)//如果是路,且步数较少,则更新 { dp[x][y][nowkey] = nowstep + 1; que.push(Node(x , y , nowkey , nowstep + 1)); } } } } return -1; } int main() { while(scanf("%d%d%d",&n,&m,&t) != EOF) { int i , j , k; string ss; for(i = 1;i <= n;i++) { cin >> ss; for(j = 0;j < m;j++) { jail[i][j + 1] = ss[j]; if(ss[j] == '@') { s.x = i; s.y = j + 1; } } } s.key = 0; s.step = 0; for(i = 1;i <= n;i++) for(j = 1;j <= m;j++) for(k = 0;k < (1<<10);k++) dp[i][j][k] = inf; cout << DP() << endl; } return 0; }