题目链接:点击打开链接
题意:
'$'和'!'是2个人,'*'是终点。
'A'-'Z' 字母是26种传送门,每种传送门可以到瞬间同字母(不同字母间不能移动)
问2个人中慢的那个到达终点的步数。
可以往8个方向走。
思路:
bfs
把同字母的点当成一个点。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
#define N 10115
#define M (N*33)
struct Edge{
int to, dis, nex;
}edge[M];
int head[N], edgenum;
int step[8][2] = {-1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1};
void init(){memset(head, -1, sizeof head); edgenum = 0;}
void add(int u, int v, int d){
Edge E = {v, d, head[u]};
if(edgenum>=M)while(1);
edge[edgenum] = E;
head[u] = edgenum++;
}
int n, m;
char s[115][115];
bool inmap(int x, int y){return 1<=x&&x<=n&&1<=y&&y<=m && s[x][y]!='#';}
void put(int dis[]){int top = 1; for(int i = 1; i <=n; i++){for(int j= 1;j<=m;j++)printf(" %d",dis[top++]);puts("");}}
int Hash(int x, int y){return (x-1)*m+y;}
bool inq[N];
int bfs(int from, int to, int dis[]){
int top = 1;
for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++){
dis[top++] = -1;
}
memset(inq, 0, sizeof inq);
dis[from] = 0;
queue<int>q; q.push(from);
while(!q.empty()){
int u = q.front(); q.pop(); inq[u] = 0;
for(int i = head[u]; ~i; i = edge[i].nex){
int v = edge[i].to;
if(dis[v]==-1 || dis[v]>dis[u]+edge[i].dis){
dis[v] = dis[u]+edge[i].dis;
if(!inq[v] && v!=to)inq[v] = 1, q.push(v);
// put(dis);
}
}
}
// put(dis);
return dis[to];
}
int from1, from2, to, dis1[N], dis2[N], tx, ty;
vector<int>G[27];
int solve(){
int ans1 = bfs(from1, to, dis1);
if(ans1==-1)return -1;
// printf(" dis1 : %d\n", ans1);
int ans2 = bfs(from2, to, dis2);
if(ans2==-1)return -1;
// printf(" dis2 : %d\n", ans2);
int ans = -1;
for(int i = 0; i < 8; i++){
int x = tx + step[i][0], y = ty + step[i][1], d = Hash(x,y);
if('A'<=s[x][y]&&s[x][y]<='Z') d = G[s[x][y]-'A'][0];
if(!inmap(x,y) || dis1[d]==-1 || dis2[d]==-1)continue;
if(ans==-1 || ans > max(dis1[d], dis2[d]))
ans = max(dis1[d], dis2[d]);
}
if(ans==-1)return -1;
return ans+1;
}
int main() {
while (~scanf("%d %d", &n, &m)) {
init();
for(int i = 1; i <= n; i++) {
scanf("%s", s[i]+1);
for(int j = 1; j <= m; j++)
if(s[i][j]=='*')
to = Hash(i,j), tx = i, ty = j;
else if(s[i][j]=='$')
from1 = Hash(i,j);
else if(s[i][j]=='!')
from2 = Hash(i,j);
else if('A'<=s[i][j]&&s[i][j]<='Z'){
if((int)G[s[i][j]-'A'].size()==0)
G[s[i][j]-'A'].push_back(Hash(i,j));
}
}
// printf("end:(%d,%d), to=%d, from1=%d, from2=%d\n",tx,ty,to,from1,from2);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
if(inmap(i,j))
for(int z = 0; z < 8; z++)
{
int x = i+step[z][0], y = j+step[z][1];
if(!inmap(x,y))continue;
int u = Hash(i,j), v= Hash(x,y);
if('A'<=s[i][j]&&s[i][j]<='Z')u = G[s[i][j]-'A'][0];
if('A'<=s[x][y]&&s[x][y]<='Z')v = G[s[x][y]-'A'][0];
if(u!=v)
add(u,v,1);
}
int ans = solve();
if(ans==-1)puts("Impossible");
else printf("%d\n",ans);
for(int i = 0; i < 26; i++)G[i].clear();
}
return 0;
}
/*
1 3
$*!
1 3
*!$
7 3
!#$
A#B
###
B#A
#C#
###
C.*
5 5
#A##$
#.*#A
#.B##
#####
!..B#
*/