BZOJ2143 飞飞侠 最短路
题意:(这题没图不好说……大家还是自己去看吧)
题解:
首先有一点需要注意,就是题面中a和b数组搞混了……
像势能分析那样,我们每花费一定金额b[i][j]就相当于得到了a[i][j]的势能,这样我们建图,图中每一个点均由花费(边权)、横纵坐标、势能四个量决定,显然转移的时候有:
势能==0:向下一个点转移时加上b[i][j],势能=a[i][j]
势能!=0:每次只往上下左右移动一格或者不动,势能-=1
然后跑最短路即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <queue> #include <cstdio> #include <climits> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int INF=1000000000+2; const int X[]={0,0,1,-1,0}; const int Y[]={1,-1,0,0,0}; const char T[]={0,'X','Y','Z'}; const int MAXN=150+2; struct NODE{ int d,x,y,w; NODE(){} NODE(int _d,int _x,int _y,int _w):d(_d),x(_x),y(_y),w(_w){}; }t; bool operator<(NODE a,NODE b){ return a.d<b.d;} int a[MAXN][MAXN],b[MAXN][MAXN],w[MAXN][MAXN][2*MAXN],s[4],e[4],N,M,ans=INF,ans_t; bool flag[MAXN][MAXN][2*MAXN]; priority_queue<NODE> q; bool Check(int x,int y,int w){ if(!x || !y) return 0; if(x>N || y>M) return 0; if(flag[x][y][w-1]) return 0; return 1; } void Dijkstra(int x,int y){ while(!q.empty()) q.pop(); for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) for(int k=0;k<=N+M-2;k++) w[i][j][k]=INF; memset(flag,0,sizeof(flag)); flag[x][y][0]=1,w[x][y][a[x][y]]=b[x][y]; q.push(NODE(b[x][y],x,y,a[x][y])); while(!q.empty() && (!flag[s[1]][e[1]][0] || !flag[s[2]][e[2]][0] || !flag[s[3]][e[3]][0])){ t=q.top(),q.pop(); if(flag[t.x][t.y][t.w]) continue; flag[t.x][t.y][t.w]=1; if(t.w>0) for(int i=0;i<5;i++){ if(Check(t.x+X[i],t.y+Y[i],t.w) && w[t.x+X[i]][t.y+Y[i]][t.w-1]>w[t.x][t.y][t.w]){ w[t.x+X[i]][t.y+Y[i]][t.w-1]=w[t.x][t.y][t.w]; q.push(NODE(w[t.x+X[i]][t.y+Y[i]][t.w-1],t.x+X[i],t.y+Y[i],t.w-1)); } } else if(w[t.x][t.y][a[t.x][t.y]]>w[t.x][t.y][0]+b[t.x][t.y]){ w[t.x][t.y][a[t.x][t.y]]=w[t.x][t.y][0]+b[t.x][t.y]; q.push(NODE(w[t.x][t.y][a[x][y]],t.x,t.y,a[t.x][t.y])); } } } int main(){ freopen("BZOJ2143.in","r",stdin); freopen("BZOJ2143.out","w",stdout); scanf("%d %d",&N,&M); for(int i=1;i<=N;i++){ for(int j=1;j<=M;j++){ scanf("%d",&a[i][j]); a[i][j]=min(a[i][j],max(N+M-i-j-2,i+j-2)); } } for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) scanf("%d",&b[i][j]); for(int i=1;i<=3;i++) scanf("%d %d",s+i,e+i); int a1,a2,b1,b2,c1,c2; Dijkstra(s[1],e[1]),a1=w[s[2]][e[2]][0],a2=w[s[3]][e[3]][0]; Dijkstra(s[2],e[2]),b1=w[s[1]][e[1]][0],b2=w[s[3]][e[3]][0]; Dijkstra(s[3],e[3]),c1=w[s[1]][e[1]][0],c2=w[s[2]][e[2]][0]; if(b1+c1<ans) ans_t=1,ans=b1+c1; if(a1+c2<ans) ans_t=2,ans=a1+c2; if(a2+b2<ans) ans_t=3,ans=a2+b2; if(ans==INF) printf("NO\n"); else printf("%c\n%d\n",T[ans_t],ans); fclose(stdin);fclose(stdout); return 0; }