首页 > 其他分享 >最短路问题

最短路问题

时间:2023-04-27 17:35:47浏览次数:45  
标签:存储 dist int 短路 问题 算法 quad 号点

\[最短路 \begin{cases} \ 单源最短路 \quad \begin{cases}\ 所有边权都是正数 \quad \begin{cases}\ 朴素Dijkstra算法 \quad \\[3ex] 堆优化版Dijkstra算法 \quad \end{cases}\ \\[5ex] 存在负权边 \quad \begin{cases}\ Bell-Ford算法 \quad \\[3ex] SPFA算法 \quad \end{cases}\ \end{cases}\ \\[7ex] 多源汇最短路 \quad Floyd算法 \end{cases}\ \]




朴素Dijkstra算法

朴素Dijkstra 基本思想:

集合 s 存储当前已确定最短距离的点

①dist [ 1 ] = 0 , dist [ i ] = + $ \infty $

②迭代\(\quad\)\(\quad\)for i : 1 ~ n

\(\quad\)\(\quad\)\(\quad\)​\(\quad\)\(\quad\)\(\quad\)t \(\gets\) 不在s中的, 距离最近的点

\(\quad\)\(\quad\)\(\quad\)​\(\quad\)\(\quad\)\(\quad\)s \(\gets\) t

\(\quad\)\(\quad\)\(\quad\)​\(\quad\)\(\quad\)\(\quad\)用t更新其他点

边的存储方式

  • 稠密图 —— 邻接矩阵
  • 稀疏图 —— 邻接表

//朴素Dijkstra算法模板

int g[N][N];	//存储每条边
int dist[N];	//存储1号点到每个点的最短距离
bool st[N];		//存储每个点的最短路是否已确定

//求1号点到n号点的最短路,如果不存在则返回-1
int dijkstra()
{
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    
    for(int i=0;i<n;i++)
    {
        int t=-1;	//在还未确定最短路的点中,寻找距离最小的点
        for(int j=1;j<=n;j++)
            if(!st[j]&&(t==-1||dist[t]>dist[j]))
                t=j;
        
        //用t更新其他点的距离
        for(int j=1;j<=n;j++)
            dist[j]=min(dist[j],dist[t]+g[t][j]);
        
        st[t]=true;
    }
    
    if(dist[n]==0x3f3f3f3f)return -1;
    return dist[n];
}



堆优化版Dijkstra算法

//堆优化版Dijkstra算法模板
typedef pair<int,int> PII;

int n;		//点的数量
int h[N],w[N],e[N],ne[N],idx;	//邻接表存储所有边
int dist[N];		//存储所有点到1号点的距离
bool st[N];			//存储每个点的最短路是否已确定

//邻接表存储所有边
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

//求1号点到n号点的最短距离,如果不存在则返回-1
int dijkstra()
{
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    priority_queue <PII,vector<PII>,greater<PII>> heap;
    heap.push({0,1});
    
    while(heap.size())
    {
        auto t=heap.top();
        heap.pop();
        int ver=t.second,distance=t.first;
        
        if(st[ver])continue;
        st[ver]=true;
        
        for(int i=h[ver];i!=-1;i=ne[i])
        {
            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;
    return dist[n];
}



Bellman - Ford算法

Bellman - Ford算法基本思想:

迭代\(\quad\)\(\quad\)for n次 (迭代k次,表示经过不超过k条边)

​\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)for 所有边a, b, w \(a \stackrel{w}{\rightarrow} b\)

\(\quad\)\(\quad\)​\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)dist[b] = min (dist[b] , dist[a] + w)


//Bell-Ford算法模板

int n,m,k;		//n表示点数,m表示边数,k表示经过不超过k条边
int dist[N];	//dist[x]用于存储1到x的最短距离
int backup[N];	//backup[x]用于备份数组dist[N]

Struct Edge		//存储边
{
    int a,b,w;
}edge[N];

//求1到n经过不超过k条边的最短路距离,如果无法从1走到n则返回-1
int bellman_ford()
{
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    
    for(int i=0;i<k;i++)
    {
        memcpy(backup,dist,sizeof dist);
        
        for(int j=0;j<m;j++)
        {
            int a=edges[i].a,b=edges[i].b,w=edges[i].w;
            dist[b]=min(dist[b],backup[a]+w);
        }
    }
    
    if(dist[n]>0x3f3f3f3f/2)return -1;
    return dist[n];
}



SPFA算法

//spfa算法模板

int n;		//总点数
int h[N],w[N],e[N],ne[N],idx;		//邻接表存储所有边
int dist[N];		//存储每个点到1号点的最短距离
bool st[N];			//存储每个点是否在队列中

//邻接表存储所有边
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

//求1号点到n号点的最短路距离,如果从1号点无法走到n号点则返回-1
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];
                if(!st[j])	//如果队列中已存在j,则不需要将j重复插入
                {
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
    
    if(dist[n]==0x3f3f3f3f)return -1;
    return dist[n];
}

//spfa判断图中是否存在负环模板

int n;		//总点数
int h[N],w[N],e[N],ne[N],idx;		//邻接表存储所有边
int dist[N],cnt[N];			//dist[x]存储1号点到x号点的最短距离,cnt[x]存储1到x的最短路中经过的点数
bool st[N];			//存储每个点是否在队列中

//如果存在负环,则返回true,否则返回false
bool spfa()
{
    //不需要初始化dist数组
    //原理:如果某条最短路径上有n个点(除了自己),那么加上自己之后一共有n+1个点,由鸽巢原理一定有两个点相同,所以存在环
    
    queue<int>q;
    for(int i=1;i<=n;i++;i++)
    {
        q.push(i);
        st[i]=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];
                cnt[j]=cnt[t]+1;
                if(cnt[j]>=n)return true;
                //如果从1号点到x的最短路中包含至少n个点(不包括自己),则说明存在环
                
                if(!st[j])
                {
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
    
    return false;
}



Floyd算法

Floyd算法基本思想

邻接矩阵 d[i, j] 存储每一条边

初始化三重循环\(\quad\)for(int k = 1 ; k <= n ; k++ )

​\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)for(int i = 1 ; i <= n ; i++ )

\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)for(int j = 1 ; j <= n ; j++ )

​\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)\(\quad\)d[i, j] = min(d[i, j] , d[i, k] + d[k, j])


//Floyd算法模板

//初始化
for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
        if(i==j)d[i][j]=0;
		else d[i][j]=0x3f3f3f3f;

//算法结束后,d[a][b]表示a到b的最短距离
void floyd()
{
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}


标签:存储,dist,int,短路,问题,算法,quad,号点
From: https://www.cnblogs.com/evilboy/p/17359555.html

相关文章

  • springboot分页插件的问题
    1:maven依赖的问题此类原因是与pom.xml文件中引入的分页依赖有关,由于springboot本身集成pagerhelper的分页插件,只需要引入如下依赖即可<!--spring-bootmybatispagehelper--><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-st......
  • 前端JavaScript的精确计算问题
    问题发现"47.900000"*"771.65" = 36962.034999999996 (错误)  36962.035(正确)问题定位JavaScript前端计算不精确(浮点数计算的精确问题)问题解决除法函数,用来得到精确的除法结果说明:javascript的除法结果会有误差,在两个浮点数相除的时候会比......
  • 线上问题排查回答(转载)
    面试官:「你是怎么定位线上问题的?」这个面试题我在两年社招的时候遇到过,前几天面试也遇到了。我觉得我每一次都答得中规中矩,今天来梳理复盘下,下次又被问到的时候希望可以答得更好。下一次我应该会按照这个思路去答:1、如果线上出现了问题,我们更多的是希望由监控告警发现我们出了......
  • GridView 同行item高度不一致问题
    GridView同行item高度不一致问题//bug场景:item高度不一致,存在留白间隙 解决办法:将GridView添加到它本身的适配器当中,新增ViewHolder(目的是在GridView初始化完成后,适配器方便操作GridView,直接在适配器getView方法中对converView进行操作),计算GridView高度,并设置GridView......
  • java处理逻辑表达式计算问题
    在处理SQL的where条件时,发现逻辑运算表达式不是那么简单,并不是一种线型计算结构。但是表达式树的计算又是SQL查询引擎的核心,SQL的抽象语法树最终还是要转换为表达式树来处理。所以基于原来的表达式案例,进行简单的升级,写了一个简单的逻辑表达式处理器。首先我们的逻辑表达式的操......
  • 解决Kibana(OpenSearch)某些字段无法搜索问题
    背景最近在OpenSearch查看线上日志的时候,发现某个索引下有些字段无法直接在界面上筛选,搜索到也不高亮,非常的不方便,就像下面这样字段左侧两个筛选按钮禁用了无法点击,提示Unindexedfiledscannotbesearched右侧则有感叹号提示Nocachedmappingforthisfield.Refresh......
  • 解决docker in docker http推送问题
    FROMdocker:18.09-dindENVDOCKER_HOST=unix:///var/run/docker.sockADD./main/bin/RUNmkdir-p/etc/docker&&echo-e'{"insecure-registries":["ip:5000"]}'>/etc/docker/daemon.jsonENTRYPOINT["/usr/local/......
  • 生产者消费者问题
    1、//condition_variable::notify_one#include<iostream>//std::cout#include<thread>//std::thread#include<mutex>//std::mutex,std::unique_lock#include<condition_variable>//std::condi......
  • Grid/RAC 11.2.0.4 与 Linux 7 的一些兼容性问题
    1、在LINUX6上安装11.2.0.4的RAC,基本上不会遇到什么问题,但如果在LINUX7上安装11.2.0.4的RAC,经常性地会遇到问题。为了很好地解决这个问题,ORACLE官方在MOS上给了一篇文档《Installationwalk-through-OracleGrid/RAC11.2.0.4onOracleLinux7(DocID1951613.1)》,这篇文档......
  • 使用ethtool排查网卡速率问题
    今天去现场帮一个客户排查备份网络速率问题。用户期望是万兆的速率,但实际上目前只有千兆,因为目前上面运行着数据库,且数据量较大,千兆的备份网络速率不能满足用户备份数据库的时长要求。首先,确认备份网络是由两块网卡(eth3,eth4)做了bonding,起名为bondeth1。使用ethtool查看底层的et......