D87 分层图最短路 Dijkstra 算法 UVa1078 Steam Roller

D87 分层图最短路 Dijkstra 算法 UVa1078 Steam Roller_哔哩哔哩_bilibili

 

UVA1078 Steam Roller - 洛谷

Steam Roller - UVA 1078 - Virtual Judge

给一个带边权的方格图,沿直线匀速运动,边权不变。转向前后,因为速度需要变为 0,所以转向前后的边权加倍。

当然连接起点和终点的边权也要加倍,注意,一条边两端的速度均为 0 时,边权仅加倍。求起点到终点的最短路。

image

思路

连边与点的状态有关,点有向上、向右、向下、向左和静止 五种状态,所以把每个点拆成 5 个点

给格点按行列编号,写个开点函数 id(x,y)=(x-1)*C+y,再令 n=R*C,那么,

每个格点的五个拆点依次为:id(x,y),id(x,y)+n,id(x,y)+2∗n,id(x,y)+3∗n,id(x,y)+4∗n

起点 (r1,c1) 和终点 (r2,c2) 都是静止点,所以 s = id(r1,c1)+4*n,t = id(r2,c2)+4*n

建图分四种情况:

  1. 同向的动点到动点连边,边权为 w
  2. 同向的静点到动点连边,边权为 2w
  3. 同向的动点到静点连边,边权为 2w
  4. 同向的静点到静点连边,边权为 2w

    image

点数 N = 100*100*5 = 5e4,边数 M = 100*100*4*4 = 16e4

相关板子:

D75【模板】分层图最短路 Dijkstra 算法 P4568 [JLOI2011] 飞行路线 - 董晓 - 博客园

 

// 分层图最短路 Dijkstra 算法 O(Mlogn)
#include<bits/stdc++.h>
using namespace std;

const int N=50010,M=16e4;
const int dx[]={-1,0,1,0},dy[]={0,1,0,-1}; //上,右,下,左

int idx,h[N],ne[M],to[M],ww[M];
void add(int u,int v,int w){
  to[++idx]=v,ww[idx]=w,ne[idx]=h[u],h[u]=idx;
}
int R,C,r1,c1,r2,c2,n,s,t;
int d[N]; bool vis[N];
int G[105][105][4];

void Dijkstra(){
  memset(d,0x3f,sizeof(d)),d[s]=0;
  memset(vis,0,sizeof(vis));
  priority_queue<pair<int,int> >q;
  q.push({0,s});
  while(!q.empty()){
    int u=q.top().second; q.pop();
    if(vis[u])continue; vis[u]=true;
    for(int i=h[u]; i; i=ne[i]){
      int v=to[i],w=ww[i];
      if(d[v]>d[u]+w){
        d[v]=d[u]+w;
        q.push({-d[v],v});
      }
    }
  }
}
int id(int x,int y){ //格点的编号
  return (x-1)*C+y;
}
int main(){
  if(scanf("%d %d %d %d %d %d",&R,&C,&r1,&c1,&r2,&c2)==EOF||!R) return 0;
  
  n=R*C; s=id(r1,c1)+4*n; t=id(r2,c2)+4*n; //起点编号,终点编号
  memset(G,0,sizeof(G));
  memset(h,0,sizeof(h)); idx=0;
  
  for(int i=1,t;i<=R;++i){
    for(int j=1;j<C;++j)scanf("%d",&t),G[i][j][1]=G[i][j+1][3]=t; //[i,j]右侧 [i,j+1]左侧的横边
    if(i!=R)for(int j=1;j<=C;++j)scanf("%d",&t),G[i][j][2]=G[i+1][j][0]=t; //[i,j]下面 [i+1,j]上面的竖边
  }
  
  for(int x=1;x<=R;++x)for(int y=1;y<=C;++y){
    for(int t=0;t<4;++t){ //上0,右1,下2,左3
      int nx=x+dx[t],ny=y+dy[t];
      if(nx<1||nx>R||ny<1||ny>C) continue;
      int w=G[x][y][t];
      if(!w) continue;
      add(id(x,y)+t*n,id(nx,ny)+t*n,w);   //同向的动点到动点连边
      add(id(x,y)+t*n,id(nx,ny)+4*n,2*w); //同向的动点到静点连边
      add(id(x,y)+4*n,id(nx,ny)+t*n,2*w); //同向的静点到动点连边
      add(id(x,y)+4*n,id(nx,ny)+4*n,2*w); //同向的静点到静点连边
    }
  }
  
  Dijkstra();
  static int Case=0;
  printf("Case %d: ",++Case);
  if(d[t]==0x3f3f3f3f) printf("Impossible\n");
  else printf("%d\n",d[t]);
  main();
}
 

 

posted @ 2026-02-25 23:54  董晓  阅读(100)  评论(0)    收藏  举报