ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

SPFA算法(SLF优化)2022.7.8更新

2022-07-08 22:02:36  阅读:148  来源: 互联网

标签:int spfa dfs 负环 SPFA 2022.7 SLF 写法 dis


SPFA可能会被卡掉,能用dijkstra就别用SPFA,代码较长,但我已尽力做到解释,请耐心看下去,存储为邻接表存储。

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f//(宏定义一个很大的值,例如0x3f3f3f3f等) 
using namespace std;
int n,m,cnt;//cnt 计数器(有cnt条边) 
struct edge//结构体定义 
{
    int v,w,nxt;//v 目标点 w 边权 nxt 这条边的上一条边(遍历) 
};
edge e[3000010];//存边(边表) 
int dis[3001000];//记录起点到第x个点的距离 
int h[1001000];//记录第x个点所发出的最后一条边 
bool f[1001000];//判断是否在队列内 
deque<int> q;//双端队列 
void add(int,int,int);
void spfa()//SLF优化 
{
    for(int i=1;i<=n;++i)
    {
        dis[i]=inf;
    }//初始化,也可以用memset() 
    dis[1]=0;//起点到自己的距离为0 (该题起点为1) 
    q.push_back(1);//起点入队 
    f[1]=1;//标志起点已入队 
    while(!q.empty())
    {
        int top=q.front();//取队首元素 
        q.pop_front();//踢出队列 
        int w=dis[top];//w 起点的值 
        f[top]=0;//代表该元素已出队 
        for(int i=h[top];i;i=e[i].nxt)//邻接表遍历每一条边 
        {
            int v=e[i].v;//目标点 
            int di=e[i].w;//边权 
            if(dis[v]>w+di)//松弛操作 
            {
                dis[v]=w+di;//更新起点到点v的值 
                if(!f[v])//判断是否入队,没入队便入队 
                {
                    if(!q.empty()&&dis[v]<dis[q.front()])//如果比队首元素小,从队首入队 
                    {//这里一定要把!q.empty()放在前面,编译时它会从前往后读,如果把它放后面而队列又为空,dis[v]<dis[q.front()]调用时会RE 
                        q.push_front(v);//入队操作 
                    }
                    else    q.push_back(v);//否则从队尾入队 
                    f[v]=1;//标志已入队 
                }
            }
        }
    }
}
int main()
{
    memset(h,0,sizeof h);//数组初始化 
    memset(f,false,sizeof f);//数组初始化 
    scanf("%d%d",&n,&m);
    for(int a,b,c,i=1;i<=m;++i)
    {
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c); //加边 
        add(b,a,c);//加边,如果是有向图,删掉这一步操作 
    }
    spfa();//调用函数 
    printf("%d",dis[n]);//输出,根据题目要求,这里是输出1到n的最短距离 
    return 0;
}
void add(int u,int v,int w)
{
    e[++cnt].v=v;//cnt 边的编号 
    e[cnt].w=w;
    e[cnt].nxt=h[u];//指向上一条边 
    h[u]=cnt;//更新最后一条边 
}

 2022.7.8更新:

新增判断负环的写法和dfs写法

dfs写法判断负环更快,但求答案很慢

bfs队列写法求答案快,但判断负环很慢

根据题目情况来

bfs队列写法:

bool spfa()
{
    for(rint i=1;i<=n;++i)
        dis[i]=0x7ffffff;
    dis[0]=0;
    q.push_back(0);
    vis[0]=true;
    ++in[0];//差记录入队次数
    while(!q.empty())
    {
        int u=q.front();
        q.pop_front();
        vis[u]=false;
        for(rint i=h[u];i;i=e[i].nxt)
        {
            int v=e[i].v;ll w=e[i].w;
            if(dis[v]>dis[u]+w)
            {
                dis[v]=dis[u]+w;
                if(!vis[v])
                {
                    ++in[v];
                    if(in[v]>=n+1)    return false;//判断负环 
                    if(!q.empty()&&dis[v]<dis[q.front()])    q.push_front(v);
                    else    q.push_back(v);
                    vis[v]=true;
                }
            }
        }
    }
    return true;
}

dfs写法:

void dfs_spfa(int u)
{
    if(fg)    return;
    vis[u]=true;
    for(rint i=h[u];i;i=e[i].nxt)
    {
        int v=e[i].v;
        ll w=e[i].w;
        if(dis[v]>dis[u]+w)
        {
            dis[v]=dis[u]+w;
            if(vis[v]==true)//如果这个点被访问过,就说明这是负环 
            {
                fg=true;//打标记 
                return;
            }
            else    dfs_spfa(v);
        }
    }
    vis[u]=false;
}

 

标签:int,spfa,dfs,负环,SPFA,2022.7,SLF,写法,dis
来源: https://www.cnblogs.com/yifan0305/p/16391419.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有