P4473 [国家集训队]飞飞侠
链接
题解
又见拆路径做法。
显然是要求三个单源最短路,但是边数可能是 \(n^4\) 的,难以接受。
注意到每个点向每一层连的都是区间,所以其实可以用线段树优化建图,边数变成 \(n^3\log n\),Dij 时间复杂度为 \(O(n^3\log n\log(n^3\log n))\),大概可以过,懒得写。
然后一种拆路径的做法是相当于给每个位置加上一维高度,高度为 \(0\) 时可以花费 \(a_{i,j}\) 走到顶部;高度不为 \(0\) 时可以只需高度减一并走到上下左右或不动。(Orz ldx)
有了不动就可以走到距离合法的所有位置。此时点数 \(nm(n+m)\),边数 \(5nm(n+m)\),然后这种方法可以不用存边。
code
#include<bits/stdc++.h>
using namespace std;
#define cs const
#define in read()
inline int read(){
int p=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){p=p*10+c-48;c=getchar();}
return p*f;
}
cs int N=155;
int dis[N][N][N<<1][3];
int vis[N][N][N<<1];
int n,m,a[N][N],b[N][N];
int xx,xy,yx,yy,zx,zy;
struct llmmkk{
int d,x,y,k;
friend bool operator<(const llmmkk &a,const llmmkk &b){
return a.d>b.d;
}
};
priority_queue<llmmkk>q;
int tx[5]={-1,0,1,0,0},ty[5]={0,1,0,-1,0};
inline void Dij(int sx,int sy,int tp){
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int t=0;t<=n+m;t++)
dis[i][j][t][tp]=1000000000,vis[i][j][t]=0;
q.push({0,sx,sy,0});dis[sx][sy][0][tp]=0;
while(!q.empty()){
int x=q.top().x,y=q.top().y,k=q.top().k;q.pop();
if(vis[x][y][k])continue;vis[x][y][k]=1;
if(!b[x][y]&&!k)continue;
if(k==0){
for(int t=0;t<5;t++){
int ttx=x+tx[t],tty=y+ty[t],ttk=b[x][y]-1;
if(ttx<1||ttx>n||tty<1||tty>m)continue;
if(dis[ttx][tty][ttk][tp]>dis[x][y][k][tp]+a[x][y]){
dis[ttx][tty][ttk][tp]=dis[x][y][k][tp]+a[x][y];
if(!vis[ttx][tty][ttk])
q.push({dis[ttx][tty][ttk][tp],ttx,tty,ttk});
}
}
}
else{
for(int t=0;t<5;t++){
int ttx=x+tx[t],tty=y+ty[t],ttk=k-1;
if(ttx<1||ttx>n||tty<1||tty>m)continue;
if(dis[ttx][tty][ttk][tp]>dis[x][y][k][tp]){
dis[ttx][tty][ttk][tp]=dis[x][y][k][tp];
if(!vis[ttx][tty][ttk])
q.push({dis[ttx][tty][ttk][tp],ttx,tty,ttk});
}
}
}
}
}
signed main(){
n=in,m=in;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
b[i][j]=min(n+m,in);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[i][j]=in;
xx=in,xy=in,yx=in,yy=in,zx=in,zy=in;
Dij(xx,xy,0),Dij(yx,yy,1),Dij(zx,zy,2);
int dx=dis[xx][xy][0][1]+dis[xx][xy][0][2];
int dy=dis[yx][yy][0][0]+dis[yx][yy][0][2];
int dz=dis[zx][zy][0][0]+dis[zx][zy][0][1];
if(dx>1000000000&&dy>1000000000&&dz>1000000000)cout<<"NO";
else if(dx<=dy&&dx<=dz)cout<<"X\n"<<dx;
else if(dy<=dx&&dy<=dz)cout<<"Y\n"<<dy;
else cout<<"Z\n"<<dz;
return 0;
}

浙公网安备 33010602011771号