bzoj 2143:飞飞侠

Posted 蒟蒻JHY

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 2143:飞飞侠相关的知识,希望对你有一定的参考价值。

Time Limit: 50 Sec  Memory Limit: 259 MB
Submit: 1120  Solved: 389
[Submit][Status][Discuss]

Description

飞飞国是一个传说中的国度,国家的居民叫做飞飞侠。飞飞国是一个N×M的矩形方阵,每个格子代表一个街区。然而飞飞国是没有交通工具的。飞飞侠完全靠地面的弹射装置来移动。每个街区都装有弹射装置。使用弹射装置是需要支付一定费用的。而且每个弹射装置都有自己的弹射能力。我们设第i行第j列的弹射装置有Aij的费用和Bij的弹射能力。并规定有相邻边的格子间距离是1。那么,任何飞飞侠都只需要在(i,j)支付Aij的费用就可以任意选择弹到距离不超过Bij的位置了。如下图 技术分享图片 (从红色街区交费以后可以跳到周围的任意蓝色街区。) 现在的问题很简单。有三个飞飞侠,分别叫做X,Y,Z。现在它们决定聚在一起玩,于是想往其中一人的位置集合。告诉你3个飞飞侠的坐标,求往哪里集合大家需要花的费用总和最低。

Input

输入的第一行包含两个整数N和M,分别表示行数和列数。接下来是2个N×M的自然数矩阵,为Aij和Bij 最后一行六个数,分别代表X,Y,Z所在地的行号和列号。

Output

第一行输出一个字符X、Y或者Z。表示最优集合地点。第二行输出一个整数,表示最小费用。如果无法集合,只输出一行NO

Sample Input

4 4
0 0 0 0
1 2 2 0
0 2 2 1
0 0 0 0
5 5 5 5
5 5 5 5
5 5 5 5
5 5 5 5
2 1 3 4 2 2

Sample Output

Z
15
【范围】
100% 1 < = N, M < = 150; 0 < = Aij < = 10^9; 0 < = Bij < = 1000
 
 
朴素建图的话虽然点数是m*n的,但是每个点的出边也是n*m的,显然受不了。。。
但是如果分层建图的话,虽然点是n*m*(n+m)的,但是每个点的出边数最多只有5。
所以用d[i][j][k]表示当前在(i,j)点,且最多可再免费走K次的最短路。
 
本题常数血大,一开始写spfa被卡成儿子,,,后来写dij也被卡成儿子。。。
最后加了一点小优化才过,,,,
/**************************************************************
    Problem: 2143
    User: JYYHH
    Language: C++
    Result: Accepted
    Time:13944 ms
    Memory:93240 kb
****************************************************************/
 
#include<bits/stdc++.h>
#define ll long long
#define inf 10000000000000000ll
#define maxn 155
using namespace std;
ll d[maxn][maxn][405];
bool iq[maxn][maxn][405];
char pos[4]={A,X,Y,Z};
int px[4],py[4],n,m;
ll a[maxn][maxn],ans=inf;
ll to[5][5];
int b[maxn][maxn],mxp=0;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
struct node{
    int x,y,z,dis;
    bool operator <(const node& y)const{
        return dis>y.dis;
    }
};
priority_queue<node> q;
  
inline void spfa(int y){
    memset(d,0x3f,sizeof(d));
    memset(iq,0,sizeof(iq));
    node x,z;
    d[px[y]][py[y]][0]=0,q.push((node){px[y],py[y],0,0});
    while(!q.empty()&&(!iq[px[1]][py[1]][0]||!iq[px[2]][py[2]][0]||!iq[px[3]][py[3]][0])){
        x=q.top(),q.pop();
        if(iq[x.x][x.y][x.z]) continue;
        iq[x.x][x.y][x.z]=1;
        z=x,z.z=b[x.x][x.y],z.dis=x.dis+a[x.x][x.y];
        if(z.dis<d[z.x][z.y][z.z]){
            d[z.x][z.y][z.z]=z.dis;
            q.push(z);
        }
          
        if(x.z){
            for(int i=0;i<4;i++){
                z=(node){x.x+dx[i],x.y+dy[i],x.z-1,x.dis};
                if(z.x>=1&&z.x<=n&&z.y>=1&&z.y<=m&&z.dis<d[z.x][z.y][z.z]){
                    d[z.x][z.y][z.z]=z.dis;
                    q.push(z);
                }
            }
        }
    }
    while(!q.empty()) q.pop();
     
    ll mn;
    for(int i=1;i<=3;i++){
        mn=inf;
        for(int j=0;j<=m+n;j++) mn=min(mn,d[px[i]][py[i]][j]);
        to[y][i]=mn;
    }
}
  
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            scanf("%d",&b[i][j]);
            int fat=max(i,n-i+1)+max(j,m-j+1);
            b[i][j]=min(b[i][j],fat);   
        } 
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) scanf("%lld",&a[i][j]);
    for(int i=1;i<=3;i++) scanf("%d%d",px+i,py+i);
      
    for(int i=1;i<=3;i++) spfa(i);
     
    ll now;
    for(int i=1;i<=3;i++){
        now=to[1][i]+to[2][i]+to[3][i];
        if(now<ans) ans=now,mxp=i;
    }
     
    if(ans>=inf) puts("NO");
    else printf("%c\n%lld\n",pos[mxp],ans);
    return 0;
}

 

















以上是关于bzoj 2143:飞飞侠的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 2143: 飞飞侠

刷题总结——飞飞侠(bzoj2143 最短路)

bzoj2143: 飞飞侠

BZOJ2143 飞飞侠 最短路

BZOJ 2143 飞飞侠(线段树优化建边 / 并查集优化最短路)BZOJ修复工程

BZOJ 2143 飞飞侠(线段树优化建边 / 并查集优化最短路)BZOJ修复工程