BZOJ 2143 飞飞侠(分层最短路)

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

 

考虑直接建图,点n*m,边n*n*m*m,不可行。

考虑将整个矩形再加一维,表示高度,那么对于最下面一层的点,连向的边是他对应Bij的高度,然后其他的点就向相邻位置的下一层连边。

这样点n*m*(maxBij),边n*m*(maxBij)*5.

实际上maxBij只要超过(n+m)的时候就可以到达图上任意一点,所以实际上maxBij只会<=(n+m).

然后对于三个飞飞侠跑三遍最短路即可。

 

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <bitset>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-8
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FDR(i,a,n) for(int i=a; i>=n; --i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
inline int Scan() {
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
inline void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}
const int N=155;
//Code begin....

int A[N][N], B[N][N], ps[5][2]={0,0,-1,0,1,0,0,-1,0,1};
int n, m, node[3];
LL dist[N*N*N*3], d[3][3];
bool vis[N*N*N*3];
struct qnode{
    int v;
    LL c;
    qnode(int _v=0, LL _c=0):v(_v),c(_c){}
    bool operator<(const qnode &r)const{return c>r.c;}
};
priority_queue<qnode>que;
const LL P=1LL<<60;

int get_id(int x, int y, int z){return n*m*(z-1)+(y-1)*n+(x-1);}
void Dijkstra(int nn, int start){
    int u, x, y, z, px, py, pz, id;
    mem(vis,false);
    FOR(i,0,nn) dist[i]=P;
    dist[node[start]]=0;
    while (!que.empty()) que.pop();
    que.push(qnode(node[start],0));
    qnode tmp;
    while (!que.empty()) {
        if (dist[node[0]]!=P && dist[node[1]]!=P && dist[node[2]]!=P) break;
        tmp=que.top(); que.pop();
        u=tmp.v;
        if (vis[u]) continue;
        vis[u]=true;
        z=u/(n*m)+1; y=(u%(n*m))/n+1; x=u%(n*m)%n+1;
        if (z==1) {
            pz=min(n+m,1+B[x][y]); id=get_id(x,y,pz);
            if (!vis[id]&&dist[id]>dist[u]+A[x][y]) dist[id]=dist[u]+A[x][y], que.push(qnode(id,dist[id]));
        }
        else {
            FOR(i,0,4) {
                px=x+ps[i][0]; py=y+ps[i][1];
                if (px<=0||px>n||py<=0||py>m) continue;
                id=get_id(px,py,z-1);
                if (!vis[id]&&dist[id]>dist[u]) dist[id]=dist[u], que.push(qnode(id,dist[id]));
            }
        }
    }
    FOR(i,0,2) d[start][i]=dist[node[i]];
}
int main ()
{
    int x, y;
    n=Scan(); m=Scan();
    FOR(i,1,n) FOR(j,1,m) B[i][j]=Scan();
    FOR(i,1,n) FOR(j,1,m) A[i][j]=Scan();
    FOR(i,0,2) x=Scan(), y=Scan(), node[i]=get_id(x,y,1);
    FOR(i,0,2) Dijkstra(n*m*(n+m+1),i);
    LL ans=P;
    int p;
    FOR(i,0,2) if (ans>d[0][i]+d[1][i]+d[2][i]) ans=d[0][i]+d[1][i]+d[2][i], p=i;
    if (ans==P) puts("NO");
    else {
        if (p==0) puts("X");
        else if (p==1) puts("Y");
        else puts("Z");
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2017-08-07 16:50  free-loop  阅读(298)  评论(0编辑  收藏  举报