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 }
时间: 2024-08-04 13:55:51

HDU 3619 优先队列+状压+bfs的相关文章

hdu 1429 状压bfs

#include <iostream> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #define inf 0x3f3f3f3f #define ll __in

HDU 5094 状压BFS

给出n*m矩阵 给出k个障碍,两坐标之间存在墙或门,门最多10种, 给出s个钥匙位置及编号,相应的钥匙开相应的门 状压BFS即可,注意有可能同一个位置有多个门或者多个钥匙 #include "stdio.h" #include "string.h" #include "queue" using namespace std; int b[]={1,2,4,8,16,32,64,128,256,512,1024,2048}; int dir[4][2

HDU 4012 Paint on a Wall(状压+bfs)

Paint on a Wall Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)Total Submission(s): 830    Accepted Submission(s): 325 Problem Description Annie wants to paint her wall to an expected pattern. The wall can be repr

HDU 4284Travel(状压DP)

HDU 4284    Travel 有N个城市,M条边和H个这个人(PP)必须要去的城市,在每个城市里他都必须要“打工”,打工需要花费Di,可以挣到Ci,每条边有一个花费,现在求PP可不可以从起点1走完所有的他必须要去的城市,打完所有的工,并且成功回到起点1 由于H<=15,所以显然可以状压,预处理这些都必须去的城市之间的最短距离(可以floyd),然后状压DP[S][i]表示他到达了S这些城市后正处在第i个城市里(所以S & (1<<i) != 0)的剩余的最大的钱的数量,然

[GDOI2015]推箱子(状压bfs)

[GDOI2015]推箱子(状压bfs) 题面 题面过长,略 分析 观察到$m \times m =64 \(,那么可以把箱子的01状态压到一个```unsigned long long```里面 然后对于地图上的每一个点\)(x,y)\(,预处理出左上角在\)(x,y)\(,边长为\)m\(的正方形的01状态.如果这个状态和箱子的状态按位与的结果为0,那么就说明箱子可以通过. 然后发现这类似一个分层图上的最短路问题,直接BFS即可.状态\)dist[x][y][k]\(表示箱子左上角在\)(x

HDU 4771 状压bfs

Stealing Harry Potter's Precious Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1295    Accepted Submission(s): 618 Problem Description Harry Potter has some precious. For example, his invisibl

HDU-5025 2014广州网络赛 Saving Tang Monk 状压+BFS

给出一个N*N的矩阵,开启牢门需要收集齐m种钥匙,且必须收集了前i-1种钥匙才能收集第i种钥匙,最终收集齐了回到关押唐僧的房间拯救唐僧,经过一个'S'的房间时需要额外耗时把蛇打死,蛇最多5条,所以状压一下用优先队列BFS求最小时间即可. #include <iostream> #include <cstdio> #include <cmath> #include <queue> #include <vector> #include <cst

HDU 3001 Travelling 状压DP

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题意:还是环游地图的问题,只不过这回旅行者对自己有着严格的要求,地图上每个点的经过次数不能超过两次. 思路:依然是状压DP问题,根上一道很像,只不过这次对于每个点来说有三种状态,分别是未经过,经过一次,经过两次.所以要用三进制的数来进行状态压缩,这个关键点想明白了其他的和上一道基本一样了.对于我来说需要注意的是:能够到达某一个点经过了两次的状态的前一个状态是这个点已经经过了一次的状态,而不是从来未

[题解]luogu_P4011_孤岛营救问题(状压bfs/最短路

钥匙只有10种可以状压,最短路或者bfs都行,但是写挂了(现在还是 #include<iostream> #include<cstdio> #include<cstring> #include<queue> #define pb push_back using namespace std; const int maxn=13; const int dx[]={-1,0,1,0}; const int dy[]={0,1,0,-1}; int n,m,p,k,