题目链接:点击打开链接
题意:
'$'和'!'是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# */