用d[i][j][k]表示走到第(i,j)格,在不弹射的情况下还能再走k步的最小花费,那么有转移:
d[i][j][k]->d[x][y][k-1],其中(i,j)和(x,y)相邻或相等,k>0,表示走到相邻一格或不走;
d[i][j][0]+a[i][j]->d[x][y][b[i][j]],表示一次弹射。
注意样例输入的A,B数组相反?另外听说卡spfa?
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define N 155
#define inf 1000000000
using namespace std;
const int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
int m,n,len,x1,x2,x3,y1,y2,y3,t1,t2,t3,a[N][N],b[N][N],d[N][N][N<<1];
bool vis[N][N][N<<1];
struct node{ int x,y,z,d; };
priority_queue<node> q;
bool operator <(node u,node v){ return u.d>v.d; }
void solve(int sx,int sy){
int i,j,k; while (!q.empty()) q.pop();
for (i=1; i<=m; i++)
for (j=1; j<=n; j++)
for (k=0; k<=len; k++){
vis[i][j][k]=0; d[i][j][k]=inf;
}
d[sx][sy][0]=0;
node u,v; u.x=sx; u.y=sy; u.z=u.d=0; q.push(u);
while (!q.empty() && !(vis[x1][y1][0] && vis[x2][y2][0] && vis[x3][y3][0])){
u=q.top(); q.pop();
if (vis[u.x][u.y][u.z]) continue; vis[u.x][u.y][u.z]=1;
if (u.z){
for (k=0; k<4; k++){
i=u.x+dx[k]; j=u.y+dy[k];
if (i>0 && i<=m && j>0 && j<=n && u.d<d[i][j][u.z-1]){
d[i][j][u.z-1]=v.d=u.d;
v.x=i; v.y=j; v.z=u.z-1; q.push(v);
}
}
v=u; v.z--;
if (v.d<d[v.x][v.y][v.z]){ d[v.x][v.y][v.z]=v.d; q.push(v); }
} else {
v=u; v.z=a[v.x][v.y]; v.d+=b[v.x][v.y];
if (v.d<d[v.x][v.y][v.z]){
d[v.x][v.y][v.z]=v.d; q.push(v);
}
}
}
}
int main(){
scanf("%d%d",&m,&n); int i,j;
for (i=1; i<=m; i++)
for (j=1; j<=n; j++){
scanf("%d",&a[i][j]); a[i][j]=min(a[i][j],max(i-1,m-i)+max(j-1,n-j)+1);
len=max(len,a[i][j]);
}
for (i=1; i<=m; i++)
for (j=1; j<=n; j++) scanf("%d",&b[i][j]);
scanf("%d%d%d%d%d%d",&x1,&y1,&x2,&y2,&x3,&y3);
solve(x1,y1); t2+=d[x2][y2][0]; t3+=d[x3][y3][0];
solve(x2,y2); t1+=d[x1][y1][0]; t3+=d[x3][y3][0];
solve(x3,y3); t1+=d[x1][y1][0]; t2+=d[x2][y2][0];
int ans=min(min(t1,t2),t3);
if (ans<inf){
puts((ans==t1)?"X":(ans==t2)?"Y":"Z");
printf("%d\n",ans);
} else puts("NO");
return 0;
}
by lych
2016.3.4