题目链接
Earthstone Keeper Time Limit: 4 Seconds Memory Limit: 65536 KBEarthstone Keeper is a famous roguelike game created by Lizard Entertainment. In this game, an adventurer will explore in a single layer dungeon of N × M size.
The adventurer starts at the room (SR, SC) and he wants to go to the room located at (TR, TC) since there hides a big treasure box full of gold and diamonds! However, exploration is not always an easy job. There are many traps and monsters in the dungeon. To be specific, there are 4 types of rooms:
Two rooms are adjacent if and only if they share an edge. The adventurer can take 1 minute to go from a room to an adjacent room. Traps or monsters are always dangerous. More precisely, there is a fatality value for each trap and monster. Although our adventurer is strong and swift, battling with a deadly monster or dodging a rolling stone trap are not wise options.
The dungeon has been sealed by its owner with a powerful magic so the adventurer can not escape to outside until he found the treasure. By the way, being afraid of monsters battling with each other, the dungeon owner will not set any two monster rooms adjacent to each other. The room (SR, SC) and (TR, TC) are always common rooms and will not be adjacent to any monster room.
The adventurer want choose a best path to the treasure. The total fatality value of all monsters he killed and all traps he triggered should be as low as possible (If a trap was triggered multiple times, the fatality should also count multiple times). Among all safest paths, he want to choose the shortest path lead to the treasure room.
Please write program to help the adventurer find out the best path to the treasure.
There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:
The first line contains two integers N and M (1 <= N, M <= 500). The second line contains 4 integers SR, SC, TR, TC (1 <= SR, TR <= N and 1 <= SC, TC <= M).
For the next N lines, each line contains M characters indicating the map of dungeon. Each type of room is marked as:
The fatality value of trap "a" and monster "A" is 1. The fatality value of trap "b" and monster "B" is 2, and so on. Therefore, the most dangerous trap "z" or monster "Z" has its fatality value equal to 26.
For each test case, output the total fatality value and the time cost (in minutes) of the best path, separated by a space. It is guaranteed that there always exists at least one path from (SR, SC) to (TR, TC).
1 3 5 1 1 3 5 ..b.. .#C#. ..a..
4 6
题意:在n*m的迷宫里面,有四种类型的点:
1: “.”表示正常的点,能够通过。
2:“#”表示墙,不能通过。
3:小写字母”a“到”z“,表示陷阱,走到这个点会受到伤害,‘a’表示受到1点伤害,‘b’表示2点伤害,以此类推。陷阱一直存在不会消失。
4:大写字母”A“到”Z“,表示怪兽,走到与怪兽相邻的四个点,怪兽会立即向你扑来,你必须杀死怪兽,并受到伤害。’A‘表示受到1点伤害,’B‘表示受到2点伤害,以此类推。怪兽被杀死以后不会复活。怪兽与怪兽之间一定不会相邻。
已知起点和终点,起点和终点都是正常的点,且不会与怪兽相邻。起点到终点保证至少存在一条路径。
走到相邻的点要花一个单位时间。
求从起点到终点受到的最少伤害,与在最小伤害的基础上,花的最短时间为多少?
题解:忽略怪兽的存在,容易看出题目就是维护两个关键值的最短路问题。我们把一个格子看成一个点,相邻的点建边,边权有两个关键值,一个是伤害,一个是时间,伤害为走到边的终点受到的伤害,时间为1。
我们再来考虑怪兽的特点:
1,怪兽与怪兽之间一定不相邻
2,一旦走到怪兽相邻的点,就会受到怪兽的伤害,并杀死怪兽
3,怪兽一旦死亡,不会再复活
用一般建图的方法,会出现伤害重复计算的问题,如何处理这个问题呢?
我们把怪兽所在的点看成墙,在A,B,C,D之间建边。每个点都向其余三个点建单向边。比如以A为起点,B为终点,建单向边。边有两个权值,一个是伤害,一个是时间。伤害为B点受到的总伤害,减去A点和B点都相邻的怪兽的伤害(可能不止一个怪兽)。时间为2。
跑最短路,以伤害小优先,再以时间小优先。
代码如下:(我是写的堆优化的dij)
#include<stdio.h> #include<iostream> #include<algorithm> #include<math.h> #include<queue> #include<stack> #include<set> #include<map> #include<vector> #include<string.h> #include<string> #include<stdlib.h> typedef long long LL; typedef unsigned long long LLU; const int nn=505; const int inf=0x3fffffff; const LL inf64=(LL)inf*inf; const int mod=1000000007; using namespace std; int n,m; char tu[nn][nn]; int dir[4][2]={1,0,-1,0,0,1,0,-1}; int sx,sy,ex,ey; struct bian { int en,next; pair<int,int>len; }E[nn*nn*10]; int p[nn*nn],num; void init() { memset(p,-1,sizeof(p)); num=0; } void add(int st,int en,int len,int ti) { E[num].len=make_pair(len,ti); E[num].en=en; E[num].next=p[st]; p[st]=num++; } bool check(int dx,int dy) { if(dx<0||dx>=n||dy<0||dy>=m) return false; if(tu[dx][dy]=='#') return false; return true; } int hurt1(int x,int y) { int re=0; if(tu[x][y]>='a'&&tu[x][y]<='z') re+=tu[x][y]-'a'+1; int dx,dy,i; for(i=0;i<4;i++) { dx=dir[i][0]+x; dy=dir[i][1]+y; if(check(dx,dy)) { if(tu[dx][dy]>='A'&&tu[dx][dy]<='Z') re+=tu[dx][dy]-'A'+1; } } return re; } int hurt2(int x,int y,int xx,int yy) { int re=hurt1(xx,yy); int dx,dy; int fx,fy; int i,j; for(i=0;i<4;i++) { dx=x+dir[i][0]; dy=y+dir[i][1]; if(check(dx,dy)) { if(tu[dx][dy]>='A'&&tu[dx][dy]<='Z') { for(j=0;j<4;j++) { fx=dx+dir[j][0]; fy=dy+dir[j][1]; if(fx==xx&&fy==yy) { re-=tu[dx][dy]-'A'+1; break; } } } } } return re; } vector<pair<int,int> >ve; struct node { int id; pair<int,int>val; node(){} node(int idd,pair<int,int>vall) { id=idd,val=vall; } friend bool operator<(node aa,node bb) { return aa.val>bb.val; } }; pair<int,int>dp[nn*nn]; priority_queue<node>que; void solve() { int i; for(i=0;i<n*m;i++) { dp[i]=make_pair(inf,inf); } dp[sx*m+sy]=make_pair(0,0); que.push(node(sx*m+sy,dp[sx*m+sy])); node sta; pair<int,int>re=make_pair(inf,inf); int w; while(que.size()) { sta=que.top(); que.pop(); if(dp[sta.id]<sta.val) continue; if(sta.id==ex*m+ey) { re=min(re,dp[sta.id]); continue; } for(i=p[sta.id];i+1;i=E[i].next) { w=E[i].en; pair<int,int>tem=make_pair(sta.val.first+E[i].len.first,sta.val.second+E[i].len.second); if(dp[w]>tem) { dp[w]=tem; que.push(node(w,dp[w])); } } } printf("%d %d\n",re.first,re.second); } int main() { int i,j,k,e; int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); scanf("%d%d%d%d",&sx,&sy,&ex,&ey); sx--,sy--,ex--,ey--; for(i=0;i<n;i++) { scanf("%s",tu[i]); } init(); int dx,dy; for(i=0;i<n;i++) { for(j=0;j<m;j++) { if(tu[i][j]=='#') continue; if(tu[i][j]>='A'&&tu[i][j]<='Z') { ve.clear(); for(k=0;k<4;k++) { dx=i+dir[k][0]; dy=j+dir[k][1]; if(check(dx,dy)) { ve.push_back(make_pair(dx,dy)); } } for(k=0;k<(int)ve.size();k++) { for(e=0;e<(int)ve.size();e++) { if(e==k) continue; add(ve[k].first*m+ve[k].second,ve[e].first*m+ve[e].second,hurt2(ve[k].first,ve[k].second,ve[e].first,ve[e].second),2); } } continue; } for(k=0;k<4;k++) { dx=i+dir[k][0]; dy=j+dir[k][1]; if(check(dx,dy)) { if(tu[dx][dy]>='A'&&tu[dx][dy]<='Z') continue; add(i*m+j,dx*m+dy,hurt1(dx,dy),1); } } } } solve(); } return 0; }