BZOJ2143 飞飞侠 最短路

题意:(这题没图不好说……大家还是自己去看吧)

题解:

首先有一点需要注意,就是题面中a和b数组搞混了……

像势能分析那样,我们每花费一定金额b[i][j]就相当于得到了a[i][j]的势能,这样我们建图,图中每一个点均由花费(边权)、横纵坐标、势能四个量决定,显然转移的时候有:

势能==0:向下一个点转移时加上b[i][j],势能=a[i][j]

势能!=0:每次只往上下左右移动一格或者不动,势能-=1

然后跑最短路即可

#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;
}
View Code

 

posted @ 2017-02-27 22:44  WDZRMPCBIT  阅读(197)  评论(0编辑  收藏  举报