最短路合集

在面对不同情景下采用的不同算法
在这里插入图片描述
朴素的迪杰斯特拉算法
适用情况:稠密图(点的个数e 边的数量v 有e≈v*v)
储存图的数据结构:邻接矩阵(一个二维数组 g[【i】【j】表示点i到点j的距离)
时间复杂度 n*n;

代码说明
dist[N] 表示起始点到1到n点的距离 若不存在则为最大值(0x3f3f3f3f)
核心是找到数组dist中最小值
每次找到最小值(如果最小值为dist【t】)时 开始遍历1到n点中
dist【j】(点1到点j的距离)与dist【t】(点1到t的距离)+g【t】【j】(表示点t到点j的距离)之间的大小然后取最小值
在这里插入图片描述

在这里插入图片描述
例题1:最短路1

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = 510;

int g[N][N],dist[N];//dist表示点1到点N的距离
int n,m;
bool st[N];//来表示1到n的最短路径是否已经被确定

int cl()
{
    memset(dist,0x3f,sizeof dist);//先把dist初始化
    dist[1]=0;//起始点的距离到起始点的距离为0
    for(int i=0;i<n;i++)//开始进行n次遍历
    {
        int t=-1;//t要先初始化为-1
        for(int j=1;j<=n;j++)//结束只后可以在未确认的dist中找到最小值
        {
            if(st[j]==false&&(t==-1||dist[j]<dist[t]))
            t=j;
        }
        st[t]=true;//此时dist[t]的值已经确定 可以标记为true
        for(int j=1;j<=n;j++)
        dist[j]=min(dist[j],dist[t]+g[t][j]);//开始寻找最短路径
    }
    if(dist[n]==0x3f3f3f3f) return -1;
    else
    return dist[n];
}

int main()
{
    cin>>n>>m;
    memset(g,0x3f,sizeof g);
    while(m--)
    {
        int a,b,c;
        cin>>a>>b>>c;
        g[a][b]=min(g[a][b],c);//可能会有重边的情况 取最小的那一条
    }
    cout<<cl()<<endl;
    
    return 0;
}

堆优化的迪杰斯特拉算法:

适用情况:稀疏图(v和e接近)
储存图的数据结构:邻接表(可以看成是有许多表头的单链表)
时间复杂度:mlong(n)

邻接表的构造:

int h[N],e[N],ne[N],w[i],idx;
//h[i]是以i为顶点所能到达的所有边 是一个头结点 邻接表里面一共有n个头节点,他指向下一个节点的编号 
//e[i]储存的是具体的地点值
//ne[i]指向下一个顶点的具体值
//w[i]表示指向第i个点的这条路径的长度
//idx 与单链表一样 表示用到了那个结点

memset(h,-1, sizeof h);//在单链表里面要把头结点初始化 所以在邻接表里面要把所以的头节点初始化
//memset在头文件cstring里面

void add(int a, int b, int c)//有一条从顶点a指向顶点b长度为c的路径 
{
	w[idx]=c;//将长度储存在w里面 
	e[idx]=b;//将被指的顶点存在e里面 
	ne[idx]=h[a];//其下一个点为头结点之前指向的点,这里面的插入都是向头节点后面插入 
	h[a]=idx++;//头节点指向idx 然后idx++为下一个结点做准备 
} 

优先队列:其实就是一个小根堆 每次返回优先队列的值时(如果未声明)返回队列里面的最大值

#include<iostream>
#include<queue>

using namespace std;

int main()
{
	priority_queue<int,vector<int> > a;//大根堆,队头元素最大 
	priority_queue<int, vector<int>, greater<int> > b;//小根堆 ,队头元素最小 
	for(int i=1; i<=10; i++)
	{
		a.push(i);
		b.push(i);
	}
	//返回队头元素 
	cout<<a.top()<<endl;
	cout<<b.top()<<endl; 
}

与朴素迪杰斯特拉算法不同的是 不用每次去挨个寻找为确定的dist之中的最小值是多少 只需要返回优先队列的队头元素即可

题目: 同朴素版迪杰斯特拉
代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>

using namespace std;

const int N = 150010;

typedef pair<int,int> PII;

int h[N],ne[N],e[N],idx,w[N],dist[N];//w数组用来储存路径的权
int n,m;
bool st[N];

void add(int a,int b,int c)
{
    w[idx]=c;
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}

int djst()
{
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    //接下来要用小根堆来寻找未被确认的dist【n】中的最小值
    priority_queue<PII, vector<PII>, greater<PII>> heap;//第一个是声明
    //一个PII类型的队列,第二个是声明是那vector存储的队列,第三个是声明
    //小根堆
    heap.push({0,1});//{n,m}表示1到m号点距离为n;
    
    while(heap.size())//当优先队列非空
    {
        PII t=heap.top();//然后取其队头
        heap.pop();//将队头拿出
        int ver=t.second,distance=t.first;//ver为队头中点的值,distance为
        //距离
        
        if(st[ver]==true)//当ver这个点已经被确定过,即dist【ver】已经最小
        continue;
        st[ver]=true;
        
        for(int i=h[ver];i!=-1;i=ne[i])//开始遍历 来优化所有经过ver的路径长度
        {
            int j=e[i];//表示具体的结点值
            if(dist[j]>distance+w[i])
            {
                dist[j]=distance+w[i];
                heap.push({dist[j],j});
            }
        }
    }
    if(dist[n]==0x3f3f3f3f) return -1;
    else
    return dist[n];
    
}

int main()
{
    cin>>n>>m;
    
    memset(h,-1,sizeof h);
    
    while(m--)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
    }
    
    cout<<djst()<<endl;
    
    return 0;
    
}

弗洛伊德(Floyd)算法

特点:可以求出 任意两点之间的距离;
储存图的方法:邻接矩阵 二维数组
注意: 在储存图的时候当i=j时 g[i][j] =0;
时间复杂度: n^3;
思路: 如果要求点a到点b的最短距离时 在所有除了a,b点之外的点是否存在一个点p使得 g[a][b]>g[a][p]+g[p][b] 如果存在则令 g[a][b]=g[a][p]+g[p][b] ,此时由a到b的点就会经过p来使其距离减少,然后在所有除了a,b,p点之外的点中去寻找拥有与p点由相同性质的点,当把所有点遍历完了之后就可以找到由a到b的最短路径。

核心代码:

for(int k=1;k<=n;k++)
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
		{
			g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
		 } 

代码解释
f[i, j, k]表示从i走到j的路径上除i和j点外只经过1到k的点的所有路径的最短距离。那么f[i, j, k] = min(f[i, j, k - 1), f[i, k, k - 1] + f[k, j, k - 1]。
因此在计算第k层的f[i, j]的时候必须先将第k - 1层的所有状态计算出来,所以需要把k放在最外层。

例题2;Floyd求最短路

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 210,M=1e9;

int h[N][N];
int n,m,t;

int main()
{
    cin>>n>>m>>t;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            if(i==j) h[i][j]=0;//当i==j时要特殊处理 与迪杰斯特拉不同
            else h[i][j]=M;//给一个比较大的数
        }
    while(m--)
    {
        int a,b,c;
        cin>>a>>b>>c;
        h[a][b]=min(h[a][b],c);
    }
    
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                {
                    h[i][j]=min(h[i][k]+h[k][j],h[i][j]);
                }
    while(t--)
    {
        int x,y;
        cin>>x>>y;
        if(h[x][y]>M/2)//在这里不能能用h[x][y]==M来判断
        cout<<"impossible"<<endl;
        else
        cout<<h[x][y]<<endl;
    }
    return 0;
}

ford算法

特点:解决负权边(即路径长度为负数)
储存图的方法;一维数组(按着边的数量储存在数组中,一般用三个一维数组)
时间复杂度:o(n*m)
说明:要用到三个一维数组
v,u,w;
如果第一条边为 4 5 7 即第一条边为由点4到点5 路径为7 的边
那么v[1]=4,u[1]=5,w[1]=7;
即数组v中储存的都是出发点
数组u中储存的都是到达点
数组w中储存的是路径长度
思想: 最外层要遍历n-1次 因为最短路中最多会由n-1条边构成
内层遍历m次即把每一跳边都遍历
寻找dist[u[i]]<dist[v[i]]+w[i]的点 使dist[u[i]]=dist[v[i]]+w[i]

步骤

0.初始化dist数组为正无穷,dist[1]=0;

1.(外重循环)循环i从1到n-1,遍历n-1次

2.(内重循环)循环j从1到m,遍历m条边,把所有边都进行松弛操作;

每次取出两点以及他们连接的边的权重(a,b,w表示a—>b的一条边);

用从起点到a的当前最短距离+权重来更新从起点到b的当前最短距离;
dist[b]=min(dist[b],dist[a]+w);

3.返回答案;

例题3有边数限制的最短路

#include<iostream>
#include<algorithm>
#include<cstring>

const int N = 10010;

int v[N],u[N],w[N],dist[N],back[N];
int n,m,k;

using namespace std;

int main()
{
    cin>>n>>m>>k;
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    for(int i=1;i<=m;i++)
    {
        cin>>v[i]>>u[i]>>w[i];
    }
    for(int i=1;i<=k;i++)
    {
        memcpy(back,dist,sizeof dist);//要使用一个back数组 防止串联 
         for(int j=1;j<=m;j++)
        {
            dist[u[j]]=min(dist[u[j]],back[v[j]]+w[j]);//这里更新时要用到上次的点即去使用back中的值
        }       
    }

    if(dist[n]>0x3f3f3f3f/2) cout<<"impossible";
    else
    cout<<dist[n];
}

spfa算法
说明:spfa算法是对ford算法的优化 ford算法每次都要把m个边给遍历一遍 有的遍历是无效的 大大的提高了运算时间,所有我们只用遍历那些到源点距离变小的点所连接的边即可,只有当一个点的前驱结点更新了,该节点才会得到更新;因此考虑到这一点,我们将创建一个队列每一次加入距离被更新的结点。

st数组是用来判断某一个点是否在队列中 记住某一个点可以重复的在队列中出现 即进去后出去后还可以再进去

spfa还可以判断是否还有负权回路

图的储存方法: 邻接表

spfa算法步骤
queue <– 1(把一号点放进去)
while queue 不为空
(1) t <– 队头
queue.pop()
(2)用 t 更新所有出边 t –> b,权值为w
queue <– b (若该点被更新过,则拿该点更新其他点)

例题4 spfa求最短路

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>

using namespace std;

const int N = 2e5+10;

int h[N],ne[N],e[N],w[N],idx;
int dist[N];
int n,m;
bool st[N];

void add(int a,int b,int c)
{
    w[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

int spfa()
{
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    queue<int> q;
    q.push(1);
    st[1]=true;
    while(q.size())
    {
        int t=q.front();
        q.pop();
        st[t]=false;
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>dist[t]+w[i])
            {
                dist[j]=dist[t]+w[i];
                q.push(j);
                st[j]=true;
            }
        }
    }
	if(dist[n]==0x3f3f3f3f) return -1;
	else
	return dist[n];
}

int main()
{
    cin>>n>>m;
    memset(h,-1,sizeof h);
    while(m--)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
    }
    int ans=spfa();
    if(ans==-1) cout<<"impossible";
    else
    cout<<ans<<endl;
    
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
IGBT短路耐受时间与其跨导或增益以及IGBT芯片热容量有关。增益较高的IGBT会导致较高的短路电流,从而降低短路耐受时间。然而,较高的增益也会导致较低的通态导通损耗,需要在增益和短路耐受时间之间进权衡取舍。此外,技术的进步导致使用芯片尺寸更小,缩小了模块尺寸,但也降低了热容量,进一步缩短了短路耐受时间。因此,IGBT的短路耐受时间受到多个因素的影响,包括增益、热容量和芯片尺寸等。\[1\] #### 引用[.reference_title] - *1* [嵌入式分享合集79](https://blog.csdn.net/qq_29788741/article/details/127387986)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [关于碳化硅,不可不知的10件事!](https://blog.csdn.net/REASUNOS/article/details/127337639)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [第三代电力电子半导体:SiC MOSFET学习笔记(三)SiC驱动方案](https://blog.csdn.net/qq_41600018/article/details/121890893)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值