【图论】最短路径

最短路径算法

二维网格中伪最短路径算法

1.1293. 网格中的最短路径 - 力扣(LeetCode)

给你一个 m * n 的网格,其中每个单元格不是 0(空)就是 1(障碍物)。每一步,您都可以在空白单元格中上、下、左、右移动。

如果您 最多 可以消除 k 个障碍物,请找出从左上角 (0, 0) 到右下角 (m-1, n-1) 的最短路径,并返回通过该路径所需的步数。如果找不到这样的路径,则返回 -1 。

解法:

该题可以使用bfs来写,首先面对迷宫类问题来说,当使用bfs的时候,一旦遍历到目标点时,这时发生的步骤就是最小的,所bfs一般被用解答迷宫最短路径问题

堆优化的dij算法

存图数据结构:静态邻接表–(链式前向星)

​ 优先队列优化–用于选取最近点的

首先讲一下链式前向星代码:
在这里插入图片描述

//链式前向星--相当于头插入的链表
struct node{
    int to;//该边的终点
    int next;//相当于链表中的next
    int w;//权值
}edge[1000];//边表
int head[1000];//用与存储以该点为起点的边的位置,相当于链表的表头
int cnt=0;//用于边表的游动指针
//添加数据
void add(int x,int y,int w){
    int root=head[x];//找到以x为起点的表头
    edge[cnt].to=y;
    edge[cnt].w=w;
    edge[cnt].next=root;
    //更新表头
    head[x]=cnt;
    cnt++;
}

下面是全部代码

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
struct node {
	int to;//终点
	int w;//权值
	int next;//下一点的位置
} edge[500001];//边表
int head[500001];//表头表
int cnt = 1;//以1为开始--统一规定,防止出现边界问题
long long dic[500001] = { 0 };//点i距源点 s的距离
priority_queue<pair<int, int>, vector<pair<int,int>>, greater<pair<int, int>>> q;//用于选出最短距离的点 first--距离 second--点
int book[500001] = { 0 };//用于标记
int count1 = 0;
void add(int x, int y, int w) {
	edge[cnt].to = y;
	edge[cnt].w = w;
	edge[cnt].next = head[x];
	head[x] = cnt;
	cnt++;
}

void diji() {
	int n, m, s;
	//n--点数  m--边数  s--源点
	cin >> n >> m >> s;
	for (int i = 0; i < m; i++) {
		int x, y, w;
		cin >> x >> y >> w;
		add(x, y, w);
	}
	//初始化dic数组
	for(int i=1;i<=n;i++){
		dic[i] = 2147483647;
	}
	dic[s] = 0;
	//初始化优先队列 
	q.push(make_pair(0, s));
	while(q.size()){
		//选出最近点
		int minindex = q.top().second;//最近点的下标,第一次的弹出是源点
		q.pop();//弹出
		if (book[minindex == 1]) {
			continue;
		}
		book[minindex] = 1;
		count1++;

		//以最近点为中介点更新dic数组
		for (int i = head[minindex]; i>0; i = edge[i].next) {
			if (dic[edge[i].to] > dic[minindex] + edge[i].w) {
				dic[edge[i].to] = dic[minindex] + edge[i].w;
				q.push(make_pair(dic[edge[i].to], edge[i].to));
			}
		}
	}
	for (int i = 1; i <= n; i++) {
		cout << dic[i] << " ";
	}
	return;
}
int main() {
	diji();

	return 0;
}

Bellman-Ford算法

1.得到最小路径

2.判断图中是否存在负环

例:
在这里插入图片描述
在这里插入图片描述

P3385 【模板】负环 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

首先来了解一下可以处理负权值的Bellman-Ford

#include<iostream>
using namespace std;
//BellmanFord算法
//使用的数据结构--链式前向星
struct node{
    int to;//终点
    int w;//权值
    int next;//下一个节点
} edge[1000000];//边表
int head[1000000];//头指针
int cnt = 1;//边表计数器--从1开始,0表示空
long long dis[1000000];//距离数组
bool vis[1000000];//访问数组
int main(){

    int n,m,s;// n--点数(从1开始) m--边数 s--源点 
    cin>>n>>m>>s;
    for(int i=0;i<m;i++){
        int x,y,w;
        cin>>x>>y>>w;
        edge[cnt].to=y;
        edge[cnt].w=w;
        edge[cnt].next=head[x];
        head[x]=cnt;
        cnt++;
    }

    //初始化dic
    for(int i=1;i<=n;i++){
        dis[i]=0x3f3f3f3f3f3f;
    }
    dis[s]=0;

    //开始算法主体部分
    for(int i=1;i<=n-1;i++){
        for(int j=1;j<=m;j++){//松弛每条边,所以这里是j<=m而不是j<=n,这是与dij算法的区别
            if(dis[edge[j].to]>dis[j]+edge[j].w){
                dis[edge[j].to]=dis[j]+edge[j].w;//松弛每条边,记住这里是dis[edge[j].to]>dis[j]+edge[j].w而不是dis[edge[j].to]>dis[minindex]+edge[j].w
            }
        }
    }
    //检测负环
    for(int i=1;i<=m;i++){
        if(dis[edge[i].to]>dis[i]+edge[i].w){
            cout<<"此图存在负环"<<endl;
            return 0;
        }
    }
    //输出结果
    for(int i=1;i<=n;i++){
        cout<<dis[i]<<" ";
    }
    return 0;

}

Floyd算法

//核心算法
int n;//点个数
int m;//边个数
int map[100][100];//邻接矩阵
for(int k=0;k<n;k++){
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值