首页 > 其他分享 >必须经过关键点或达成某些状态的单源最短路-01bfs

必须经过关键点或达成某些状态的单源最短路-01bfs

时间:2022-11-20 17:24:30浏览次数:70  
标签:ny int 短路 单源 nx vis mp 01bfs op

https://ac.nowcoder.com/acm/contest/45670/D

  • 题目描述:
    小竹成功从家里逃了出来,他决定去小胖家避一避。但是小胖要求小竹带一个刺激度大于 xx 的游戏才能去他家。
    为了防止被妈妈或她的朋友发现,小竹不会在道路上行走,而是在建筑物与建筑物之间穿行。
    街道表现为一个n×m 的网格,网格上只有两种建筑: 商店和住宅。商店可以通过而住宅无法通过。
    小竹每次从当前所在网格可以行走到上下左右的网格中,但不能移动到网格的边界之外和别人的家中。正式的说,如果他在坐标为 (i,j)的网格里,他可以选择 (i+1,j) , (i,j+1) , (i - 1,j) , (i,j-1)四个方向行走。
    在位置 (i,j)(i,j) 上的商店有一个刺激度为 w{i,j}的游戏,小竹可以购买他所经过的商店中的游戏并带走。若 w{i,j} 为 -1 则代表这个位置是个住宅,无法通过。
    注意:小胖家以及小竹家均可以被通过。
    假设相邻的建筑物的距离均为 1,小竹想知道带一个刺激度高于 x 的游戏去小胖家需要的最短距离是多少?如果这是不可能实现的,请输出 −1。
  • 题目分析:意思是要在通过至少一个刺激度高于x的商店的前提下,求起点到终点的最短路。单源最短路无法解决这个问题。
  • 解法一:从起点和终点分别进行一遍bfs,双向搜索,维护两点到图上任一点的最短路径,最后枚举刺激度高于x的商店,取最小值
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int mp[2010][2010];
int n,m,x;
int sx,sy,ex,ey;
int vis[2010][2010] = {0};
int dis1[2010][2010];
int dis2[2010][2010];
struct ty{
    int x;
    int y;
    int step;
};
queue<ty> q;
int dx[4] = {1,-1,0,0};
int dy[4] = {0,0,1,-1};
int main(){
    cin>>n>>m>>x;
    cin>>sx>>sy>>ex>>ey;
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=m;j++){
            cin>>mp[i][j];
        }
    }
    memset(dis1,0x3f3f3f3f,sizeof(dis1));
     memset(dis2,0x3f3f3f3f,sizeof(dis1));
    memset(vis,0,sizeof(vis));
    q.push({sx,sy,0});
    vis[sx][sy] = 1;
    while(!q.empty()){
        ty op = q.front();
        q.pop();
        for(int i = 0 ;i<=3;i++){
            int nx = op.x+dx[i];
            int ny = op.y + dy[i];
            if(nx<1||nx>n||ny<1||ny>m||vis[nx][ny]||mp[nx][ny]==-1) continue;
            q.push({nx,ny,op.step+1});
            dis1[nx][ny] = op.step+1;
            vis[nx][ny] = 1;
        }
        
    }
    while(!q.empty()) q.pop();
    memset(vis,0,sizeof(vis));
    q.push({ex,ey,0});
    vis[ex][ey] = 1;
    while(!q.empty()){
        ty op = q.front();
        q.pop();
        for(int i = 0 ;i<=3;i++){
            int nx = op.x+dx[i];
            int ny = op.y + dy[i];
            if(nx<1||nx>n||ny<1||ny>m||vis[nx][ny]||mp[nx][ny]==-1) continue;
            q.push({nx,ny,op.step+1});
            dis2[nx][ny] = op.step+1;
            vis[nx][ny] = 1;
        }
    }
    int ans = 0x3f3f3f3f;
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=m;j++){
            if(mp[i][j]>x){
                ans = min(dis1[i][j]+dis2[i][j],ans);
            }
        }
    }
    if(ans==0x3f3f3f3f) cout<<-1<<endl;
    else
    cout<<ans<<endl;
}
解法二: 建立分层图,把图复制一遍,变成一个三维的图,对刺激度超过x的商店,假设这个商店的位置是i,j,给mp[i][j][0]与mp[i][j][1]之间连上一条边权为0的边,最后跑一遍01bfs,当走到mp[ex][ey][2]是就表示走到终点,且经过了关键点的最短路径。 解法二为普遍做法,如果题目改为至少要经过三个刺激度超过x的商店,可以多建几维的图,建到mp[i][j][3]为止,与上述方法类似,每个点最多入队一次,可在线性时间内解决。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int mp[2010][2010][2];
int n,m,x;
int sx,sy,ex,ey;
int vis[2010][2010][2] = {0};
struct ty{
    int x;
    int y; 
    int z;
    int step;
};
deque<ty> q;
int dx[4] = {1,-1,0,0};
int dy[4] = {0,0,1,-1};
int bfs(){
    memset(vis,0,sizeof(vis));
    q.push_back({sx,sy,0,0});
    while(!q.empty()){
        ty op = q.front();
        q.pop_front();
        if(vis[op.x][op.y][op.z]) continue;//访问过的点跳过
        vis[op.x][op.y][op.z] = 1;
        if(op.z<1&&mp[op.x][op.y][op.z]>x){
            q.push_front({op.x,op.y,op.z+1,op.step});
        }//通过关键点走向上一层
        if(op.x==ex&&op.y==ey&&op.z==1) return op.step;
        for(int i = 0 ;i<=3;i++){
            int nx = op.x+dx[i];
            int ny = op.y + dy[i];
            if(nx<1||nx>n||ny<1||ny>m||vis[nx][ny][op.z]||mp[nx][ny][op.z]==-1) continue;
            q.push_back({nx,ny,op.z,op.step+1});
        }
    }
    return -1;
}
int main(){
    cin>>n>>m>>x;
    cin>>sx>>sy>>ex>>ey;
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=m;j++){
            cin>>mp[i][j][0];
            mp[i][j][1] = mp[i][j][0];
        }
    }
    cout<<bfs()<<endl;
}

标签:ny,int,短路,单源,nx,vis,mp,01bfs,op
From: https://www.cnblogs.com/wujw11world/p/16908950.html

相关文章

  • 最短路相关
    0.一些前置习题1.luoguP1608路径统计实际上只需要开一个cnt记录一下到当前点的最短路有几条就行了.跑dijkstra的时候,如果是严格大于就直接把答案覆盖上,等于......
  • 集合位置(次短路模板题)
    ​​传送门​​这道题就是次短路的模板题,思路很简单,先求最短路,然后枚举最短路的每一条边,每次删去一条,然后再求最短路,对于这几次结果取最小值即可。本质的理论就是最短路和......
  • 2022NOIP A层联测29 A B C D(特殊数列 数进制数 最短路之和 一笔画)
    T1[状态压缩DP]给出\(n,m,p,q,r\),求长度是n,值域在\([1,m]\)之间的序列个数,满足\(\exists1\leqx<y<z<k\leqn,\)\(sum(x,y-1)=p,sum(y,z-1)=q,sum(z,k)=r\).(n<=50,max(p......
  • T292306 01最短路 题解
    又是一个找不到题目所以自己写的题。。。40迪杰斯特拉,但是搞不懂为什么是wa而不是re的#include<bits/stdc++.h>#definefor1(i,a,b)for(inti=a;i<=b;i++)#definell......
  • Johnson全源最短路
    Johnson全源最短路:n个点m条边Johnson全源最短路算法主要解决负环问题的全源最短路径算法主要思路:1.SPFA判断负环,在跑SPFA之前建立一个[超级源点]标号为0与每一个点之......
  • C++ 不知图系列之基于链接表的无向图最短路径搜索
    1.前言图的常用存储方式有2种:邻接炬阵。链接表。邻接炬阵的优点和缺点都很明显。优点是简单、易理解,但是对于大部分图结构而言,都是稀疏的,使用矩阵存储,空间浪费......
  • 道长的算法笔记:基础最短路模型
    #include<bits/stdc++.h>usingnamespacestd;typedefpair<int,int>ii;//移动轨迹向量化intadd[3]={+1,-1,0};intmul[3]={0,0,1};intvist[10000......
  • 最短路径树
    最短路径树,即ShortestPathTree,对于一张无向图,固定一个源点,树上每个点到源点的最短距离都等于原图中该点到源点的最短距离。最短路径树是所有路径树中边权和最小的。通......
  • SPFA最短路算法
    ShortestPathFastestAlgorithm(spfa)单源最短路、存在负权边这个算法因为与Bellman-Ford算法比较相似,只是在它的算法的基础上进行了队列优化,因此也被嘲讽为“队列优......
  • Johnson全源最短路
    Johnson通过另一种方法给每条边重新标注边权。新建一个虚拟结点0,向其他所有点连一条边权为0的边,用Bellman-Ford或SPFA算法求出0到其他所有点的最短路记为gpe[i],对于一条x->......