模板C++ 03图论算法 1最短路之单源最短路(SPFA)

3.1最短路之单源最短路(SPFA)

松弛:常听人说松弛,一直不懂,后来明白其实就是更新某点到源点最短距离。

邻接表:表示与一个点联通的所有路。

如果从一个点沿着某条路径出发,又回到了自己,而且所经过的边上的权和小于0,

就说这条路是一个负权回路。

回归正题,SPFA是bellman-ford的一种改进算法,由1994年西安交通大学段凡丁提出。它无法处理带有负环的图,判断方法:如果某个点进入队列的次数超过N次则存在负环。

SPFA的两种写法,bfs和dfs,bfs判别负环不稳定,相当于限深度搜索,但是设置得好的话还是没问题的,dfs的话判断负环很快(我也看不懂,推介宽艘)。

int n;        //表示n个点,从1到n标号
int s,t;        //s为源点,t为终点
int d[N];    //d[i]表示源点s到点i的最短路
bool vis[N];    //vis[i]=1表示点i在队列中
queue<int>q;    //队列
int spfa_dfs(int u)
{
    vis[u]=true;
    for(int k=f[u];k!=0;k=e[k].next)
    {
        int v=e[k].v,w=e[k].w;
        if(d[v]>d[u]+w)
        {
            d[v]=d[u]+w;
            if(vis[v]) return true;
            else if(spfa_dfs(v)) return true;
        }
    }
    vis[u]=false;
}

Bfs版:

/*

给出一个有N个节点,M条边的带权有向图.判断这个有向图中是否存在负权回路.

如果存在负权回路, 只输出一行-1;

如果不存在负权回路,再求出一个点S到每个点的最短路的长度.

约定:S到S的距离为0,如果S与这个点不连通,则输出NoPath.

点数N,边数M,源点S;以下M行,每行三个整数a,b,c表示点a,b之间连有一条边,权值为c

如果存在负权环,只输出一行-1,否则按以下格式输出共N行,第i行描述S点到点i的最短路:

如果S与i不连通,输出NoPath;如果i=S,输出0;其他情况输出S到i的最短路的长度

INPUT:

6 8 1

1 3 4

1 2 6

3 4 -7

6 4 2

2 4 5

3 6 3

4 5 1

3 5 4

OUTPUT:

0 6 4 -3 -2 7*/

#include<cstdio>
using namespace std;
struct point
{
    int ans;  //距离源点的最短距离
    int lson; //最后的儿子
    int p;    //被放进序列(list)的次数统计
    int v;    //是否在序列(list)中
}a[99];
struct road
{
    int x,y,c,g;//起点、终点、长度和哥哥
}b[199];
void BuildRoad(void);
void ShortRoad(int);
int list[199],n,m,s,k;//路的数量
bool bo;
int main()
{
    scanf("%d %d %d",&n,&m,&s);
    k=0;
    for(int i=1;i<=n;i++) a[i].lson=0;//放在建路之前
    for(int i=1;i<=m;i++) BuildRoad();
    bo=true;
    for(int i=1;i<=n;i++)
    {
        ShortRoad(i);//寻找负权回路
        if(bo==false)
        {
            printf("-1");
            return 0;
        }
    }
    ShortRoad(s);
    for(int i=1;i<=n;i++)
        if(a[i].ans==99999999) printf("NoPath\n");
        else printf("%d\n",a[i].ans);
}

void BuildRoad(void)
{
    int x,y,c;
    scanf("%d %d %d",&x,&y,&c);
    k++;
    b[k].x=x;
    b[k].y=y;
    b[k].c=c;
    b[k].g=a[x].lson;
    a[x].lson=k;
}

void ShortRoad(int st)
{
    for(int i=1;i<=n;i++)
    {
        a[i].ans=99999999;
        a[i].p=0;a[i].v=0;
    }
    a[st].ans=0; a[st].p=1;
    a[st].v=true; list[1]=st;
    //放入序列中
    int tou=1,wei=2;
    if(wei==n+1) wei=1;//循环数组
    while(tou!=wei)
    {
        int x=list[tou];
        for(int i=a[x].lson;i>0;i=b[i].g)
        {
            int y=b[i].y;
            if(a[y].ans>a[x].ans+b[i].c)
            {
                a[y].ans=a[x].ans+b[i].c;//松弛
                if(a[y].v==false)//如果还没有放入
                {
                    a[y].p++;
                    if(a[y].p>n)
                    {
                        bo=false;return;
                    }
                    a[y].v=0;list[wei++]=y;
                    if(wei==n+1) wei=1;
                }
            }
        }
       a[x].v=false; tou++;
       if(tou==n+1) tou=1;
    }
}

进阶:

【宽搜高级利用】最后的战犯
【两个人,一步一步。。。。】
 
最短路变例
【坐标计算】
 
【宽搜变例】【按照一定次序】密室逃脱
【bfs+dfs】
 
[JSOI2008]星球大战StarWar
【并查集+最短路】
时间: 2024-08-06 11:52:46

模板C++ 03图论算法 1最短路之单源最短路(SPFA)的相关文章

HDU 2544 最短路 (单源对短路,spfa,Dijkstra,Bellman-Ford)

题意:中文题目 思路:spfa+SLF优化.关于SPFA的详情请戳我 1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N=105, INF=0x7f7f7f7f; 4 int n, m; 5 bool vis[N]; //标记是否在队列中 6 int dest[N]; //路径长度 7 int mapp[N][N]; 8 9 10 11 int spfa(int s, int e) //求最短路径 12 { 13 me

图论-单源最短路-SPFA算法

有关概念: 最短路问题:若在图中的每一条边都有对应的权值,求从一点到另一点之间权值和最小的路径 SPFA算法的功能是求固定起点到图中其余各点的的最短路(单源最短路径) 约定:图中不存在负权环,用邻接表存储有向图,di存放从起点到结点i的最短路,q为队列,保存待处理节点 思路: 首先指定起点入队,取当前队头结点u,沿每一条与u相连的边向外扩展,对该边所指向的结点v松弛(比较当前dv与当前du加此边长,更新最短路值dv,以及最短路径prev)如果v不在队列中且更新了最短路值,v进队,直至队列中没有元

再看最短路算法 1 —— 单源最短路

学了多年的算法,最短路问题相当之常见———— 好久没写过最短路的问题了,直到昨天闲的无聊来了一题——BZOJ3402(HansBug:额才发现我弱到只能刷水的地步了TT) 一看这不是明显的单源最短路么呵呵...于是直接上来来了个dijkstra,而且用的是邻接表存储图—— Submit之后,结果却是—— 我立刻被雷到了QAQ...于是立刻改写spfa,结果—— 4000ms+(估计还不止)和192ms究竟是怎样的差距啊QAQ,本人虽然早都听说过spfa的强大性,但是未曾想过差距会如此可怕,于是H

Dijkstra算法 --- 单源最短路

Dijkstra算法适用于边权值为正的情况,可用于计算正权图上的单元最短路. 其伪代码如下: 设d[v0] = 0, 其他d[i] = INF 循环n次{ 在所有未标号的结点中,选取d值最小的结点x 给结点x加上永久标号 对于从x出发的所有边,执行松弛操作. } //松弛操作的伪代码如下: RELAX(u,v,w) if(u.d + w(u,v) < v.d){ v.d = w.d + w(u,v); pre[v] = u; } Dijkstra算法代码: /* Dijkstra 单源最短路算法

【裸单源最短路:Dijkstra算法两种版本】hdu 1874 畅通工程续

Source : hdu 1874 畅通工程续 http://acm.hdu.edu.cn/showproblem.php?pid=1874 Problem Description 某省自从实行了很多年的畅通工程计划后,终于修建了很多路.不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多.这让行人很困扰. 现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离. Input 本题目包含多组数据,请处理到文件结束.

用scheme语言实现SPFA算法(单源最短路)

最近自己陷入了很长时间的学习和思考之中,突然发现好久没有更新博文了,于是便想更新一篇. 这篇文章是我之前程序设计语言课作业中一段代码,用scheme语言实现单源最段路算法.当时的我,花了一整天时间,学习了scheme并实现了SPFA算法,那天实现之后感觉很有成就感-在这里贴出来,以飨读者. 突然发现博客园不支持scheme语言,于是只能放弃高亮了.不得不说,scheme代码有没有高亮差别好大…… ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; 题目

图论:单源最短路与多源最短路问题

转载自http://acm.uestc.edu.cn/bbs/read.php?tid=5670 下载ppt帐号:qscqesze 密码:123456 ------------------------------------------------------------------- 单源最短路径: 松弛操作:D[i]表示源点s到i的当前最短路径1.条件:d[i]+e[i][j]<d[j]2.更新:d[j]=d[i]+e[i][j] Dijkstra算法: 算法初始时d[s] = 0,其余的点

利用无权图的单源最短路算法实现地铁换乘图

//Metro.php $MetroVertex = array( 1 => '体育中心', 2 => '体育西路', 3 => '杨箕', 4 => '东山口', 5 => '烈士陵园', 6 => '农讲所', 7 => '公园前', 8 => '西门口', 9 => '陈家祠', 10 => '长寿路', 11 => '黄沙', 12 => '芳村', 13 => '花地湾', 14 => '坑口', 15 =>

单源最短路 狄克斯特拉算法

一般形式的用邻接矩阵来实现dijkstra效率比较低,我这里直接记录的是用邻接表的方法以及用优先队列加以应用. 首先解释什么是dijkstra算法 dijkstra算法 dijkstra算法适用于求单源最短路,即可以求出起点到其余各点之间的最短路.它的算法实现是一个不断更新的过程. 举一个最简单的例子,假设有这么一个图,红色表示权值,黑色表示4个点以及路径,我们假设起点为1,用d[i]来表示1到i的最短路,那么在第一轮的时候,d[2]=1,d[3]=1,d[4]=5,再下一轮的时候会对这个情况进