本题如果去掉怪物选项就是双关键字最短路。
问题是现在多了一个怪物选项,因为这个怪物选项被杀死后他不会复生,因此我们不能重复计算这个值的答案。
所以对于每条过来的路,前面一个点遇到的怪物的后面的点就不用计算了,也就是去重。
根据这个思路,我们可以得到我们想要干的是当枚举到当前点,我们希望计算出他的cost然后减去前一个点由怪物造成的cost。
所以怪物这个点是特殊的点,普通点和普通点就是按规则连边,因为他们是相邻的,去重比较容易。
我们多考虑一种连边,因为题目告诉我们怪物是不可能相邻的,这个信息显然是有自己的道理,也给我们带来启发。
当我们枚举到怪物点的时,我们将他上下左右这四个点分别连单向边,时间为2,cost就是终点的cost-起点的cost
这样就成功跳过了怪物类的点
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=2e6+10; const int mod=1e9+7; int n,m; char g[550][550]; int sx,sy,ex,ey; int dx[]={-1,0,1,0}; int dy[]={0,1,0,-1}; vector<pll> num; int h[N],ne[N],e[N],idx; int cost[N],w[N]; int st[N]; int dis[N][2]; struct node{ int x,y; int id; bool operator <(const node &t) const{ if(x==t.x) return y>t.y; return x>t.x; } }; void add(int a,int b,int c,int d){ e[idx]=b,ne[idx]=h[a],cost[idx]=c,w[idx]=d,h[a]=idx++; } bool check(int x,int y){ if(x>=0&&x<n&&y>=0&&y<m){ if(g[x][y]!='#') return true; } return false; } int solve(int x,int y){ int res=0; if(g[x][y]>='a'&&g[x][y]<='z') res+=(g[x][y]-'a'+1); int i; for(i=0;i<4;i++){ int a=x+dx[i]; int b=y+dy[i]; if(!check(a,b)) continue; if(g[a][b]>='A'&&g[a][b]<='Z') res+=(g[a][b]-'A'+1); } return res; } int get(int a,int b,int c,int d){ int res=solve(c,d); int i,j; for(i=0;i<4;i++){ int x=dx[i]+a; int y=dy[i]+b; if(check(x,y)){ if(g[x][y]>='A'&&g[x][y]<='Z'){ for(int k=0;k<4;k++){ int tmp1=dx[k]+x; int tmp2=dy[k]+y; if(check(tmp1,tmp2)){ if(tmp1==c&&tmp2==d){ res-=(g[x][y]-'A'+1); } } } } } } return res; } void dij(){ int ans1,ans2; priority_queue<node> q; q.push({0,0,sx*m+sy}); int i; for(i=0;i<=n*m;i++){ st[i]=0; dis[i][1]=0x3f3f3f3f; dis[i][0]=0x3f3f3f3f; } dis[sx*m+sy][0]=dis[sx*m+sy][1]=0; while(q.size()){ auto t=q.top(); q.pop(); if(st[t.id]) continue; st[t.id]=1; if(t.id==ex*m+ey){ ans1=t.x; ans2=t.y; break; } for(i=h[t.id];i!=-1;i=ne[i]){ int j=e[i]; if(dis[j][0]>dis[t.id][0]+cost[i]){ dis[j][0]=dis[t.id][0]+cost[i]; dis[j][1]=dis[t.id][1]+w[i]; q.push({dis[j][0],dis[j][1],j}); } else if(dis[j][0]==dis[t.id][0]+cost[i]&&dis[j][1]>dis[t.id][1]+w[i]){ dis[j][1]=dis[t.id][1]+w[i]; q.push({dis[j][0],dis[j][1],j}); } } } printf("%d %d ",ans1,ans2); } int main(){ //ios::sync_with_stdio(false); int t; cin>>t; while(t--){ scanf("%d%d",&n,&m); int i,j; idx=0; for(i=0;i<=n*m;i++){ h[i]=-1; } scanf("%d%d%d%d",&sx,&sy,&ex,&ey); sx--,sy--,ex--,ey--; for(i=0;i<n;i++) scanf("%s",g[i]); for(i=0;i<n;i++){ for(j=0;j<m;j++){ int k; if(g[i][j]=='#') continue; if(g[i][j]>='A'&&g[i][j]<='Z'){ num.clear(); for(k=0;k<4;k++){ int x=i+dx[k]; int y=j+dy[k]; if(check(x,y)){ num.push_back({x,y}); } } for(k=0;k<(int)num.size();k++){ for(int l=0;l<(int)num.size();l++){ if(k==l) continue; int tmp1=num[k].first*m+num[k].second; int tmp2=num[l].first*m+num[l].second; add(tmp1,tmp2,get(num[k].first,num[k].second,num[l].first,num[l].second),2);//计算到下个点的代价 } } } else{ for(int k=0;k<4;k++){ int x=i+dx[k]; int y=j+dy[k]; if(!check(x,y)) continue; if(g[x][y]>='A'&&g[x][y]<='Z') continue; add(i*m+j,x*m+y,solve(x,y),1); } } } } dij(); } return 0; }