首页 > 代码库 > HDU 3619 优先队列+状压+bfs

HDU 3619 优先队列+状压+bfs

Heroes of Might and Magic

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 170    Accepted Submission(s): 74


Problem Description
After a very long journey and uncountable number of uphill battles, hero Raelag (who is the transformed Agrael, notice that "Raelag" is an anagram of "Agrael") finally find the map shows where the "Holy Cap" is. Now he is going to find the treasure. 

The map is made up of squares of equal size which are arranged in r rows and c columns. At the beginning, Raelag is at the square Labeled ‘S‘, and the "Holy Cap" is at the square Labeled ‘T‘. It is guarranteed that there is only one ‘S‘ and only one ‘T‘ in a map. Squares that labeled with ‘#‘ in the map means squares that can‘t be passed; ‘.‘ means roads that can be passed without any physical loss and squares that labeled with an integer i (1 ≤ i ≤ 9) means when Raelag pass through this square, he will suffer i points of physical loss. Squares that labeled with capital letter ‘A‘, ‘B‘, ‘C‘, ‘D‘ or ‘E‘ means doors that can be passed only if Raelag has the right key (There are at most 5 kinds of doors in a map). The squares labeled with ‘S‘, ‘T‘ and other capital letters all can be passed with out physical loss. Raelag can move to squares only if that square share an edge with the square he is now in. Raelag can‘t move out of the map. 
 

 

Input
The fist line of input file contains a single integer T (1 ≤ T ≤ 10) - the number of test cases. For each test case, in the first line their are three integers: r, c and k (1 ≤ r, c ≤ 50, 0 ≤ k ≤ 5), representing the hight, length of the map and the number of kinds of doors in the map. Then there are r lines giving the map. Then k lines follows giving the position of the keys to the door ‘A‘, ‘B‘, ‘C‘, ‘D‘, and ‘E‘ in order. 

The uperleft conner is row 1 and colomn 1. 
 

 

Output
For each test case, output a single integer: the minimum points of physical lose Raelag needs to suffer to find the "Holy Cup". If he can‘t find the "Holy Cap" any way, output "-1". 
 

 

Sample Input
2
3 3 1
S21
#A#
11T
1 3
3 5 2
S..A.
##.##
.B.AT
3 1
1 5
 
 

 

Sample Output
6
-1
 
 
 
题目意思:
一个n*m迷宫,入口是S,出口是T,‘.’表示空地,可以走且不消耗能量。‘#‘表示墙,不能走。‘数字‘表示可以走且消耗对应数字的能量。‘A’--‘E’表示门,拿到对应的要是才可以走且不消耗能量。下面时k把钥匙的坐标分别对应门‘A’---‘E’。问从S到T消耗的最少能量为多少。若无法到达输出-1。
 
思路:
钥匙最多有5把,对钥匙进行状压即可,每次出队就用优先队列弹出最小能量的点。这里就不能像一般的迷宫问题那样只用二维的visited了,需要三维,前两维是坐标,第三维是此时拿到的钥匙个数。然后剩下的就是普通的迷宫问题了。
 
代码:
  1 #include <cstdio>  2 #include <cstring>  3 #include <iostream>  4 #include <algorithm>  5 #include <queue>  6 #include <vector>  7 using namespace std;  8   9 #define N 55 10  11 struct node{ 12     int x, y, step, k;           //step为消耗的能量,k为状压,表示拿到哪些钥匙 13     bool operator<(const node a)const{ 14         return a.step<step; 15     } 16 }; 17  18 struct key{ 19     int x, y; 20 }a[10];   //钥匙所在的坐标 21  22 int xx[]={1,-1,0,0}; 23 int yy[]={0,0,1,-1}; 24  25 char map[N][N]; 26 bool visited[N][N][1<<6]; 27 int stx, sty, endx, endy; 28 int n, m, k; 29  30 int bfs(){ 31     priority_queue<node>Q; 32     node p, q; 33     int i, j; 34     p.x=stx,p.y=sty,p.k=0,p.step=0; 35     Q.push(p); 36     memset(visited,false,sizeof(visited)); 37     visited[p.x][p.y][p.k]=true; 38      39     while(!Q.empty()){ 40         p=Q.top();Q.pop(); 41     //    printf("%d %d %d %d\n",p.x,p.y,p.step,p.k); 42         if(p.x==endx&&p.y==endy) return p.step; 43         for(i=0;i<4;i++){ 44             p.x+=xx[i],p.y+=yy[i]; 45             if(p.x<0||p.x>=n||p.y<0||p.y>=m||map[p.x][p.y]==#||visited[p.x][p.y][p.k]){ //若超出范围或该点是墙或这个状态已走过,那么continue 46                 p.x-=xx[i],p.y-=yy[i]; 47                 continue; 48             } 49         //    printf("1111\n"); 50             if(map[p.x][p.y]>=A&&map[p.x][p.y]<=E){      51                 if((1<<(map[p.x][p.y]-A))&p.k){    //若是门且拿到钥匙那么就可以走 52                     Q.push(p); 53                     visited[p.x][p.y][p.k]=true; 54                 } 55                 else{ 56                     p.x-=xx[i],p.y-=yy[i]; 57                     continue; 58                 } 59             } 60             else{ 61                 int keyy=p.k; 62                 for(j=0;j<k;j++){       //遍历钥匙坐标,看是否在这里,在的话就拿上 63                     if(p.x==a[j].x&&p.y==a[j].y){ 64                         p.k=(1<<j)|p.k; 65                     } 66                 } 67                 if(map[p.x][p.y]>=1&&map[p.x][p.y]<=9){   68                     p.step+=map[p.x][p.y]-0; 69                     Q.push(p); 70                     visited[p.x][p.y][p.k]=true; 71                     p.step-=map[p.x][p.y]-0; 72                 } 73                 else{ 74                     Q.push(p); 75                     visited[p.x][p.y][p.k]=true; 76                 } 77                 p.k=keyy; 78             } 79             p.x-=xx[i],p.y-=yy[i]; 80         } 81     } 82     return -1; 83 } 84  85 main() 86 { 87     int i, j; 88     int t; 89     cin>>t; 90     while(t--){ 91         scanf("%d %d %d",&n,&m,&k); 92         for(i=0;i<n;i++) scanf("%s",map[i]); 93         for(i=0;i<k;i++) scanf("%d %d",&a[i].x,&a[i].y),--a[i].x,--a[i].y; 94         for(i=0;i<n;i++){ 95             for(j=0;j<m;j++){ 96                 if(map[i][j]==S) stx=i,sty=j; 97                 else if(map[i][j]==T) endx=i,endy=j; 98             } 99         }100         int ans=bfs();101         printf("%d\n",ans);102     }103 }

 

HDU 3619 优先队列+状压+bfs