[ACM] 最短路算法整理(bellman_ford , SPFA , floyed , dijkstra 思想,步骤及模板)

以杭电2544题目为例

最短路

Problem Description

在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?

Input

输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。

输入保证至少存在1条商店到赛场的路线。

Output

对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间

Sample Input

2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0

Sample Output

3
2

Source

UESTC 6th Programming Contest Online

//bellman_ford算法,求单源到其它节点的最短路,可以处理含有负权的边,并且能判断图中是否存在负权回路(这一条在一些题中也有应用)
//无向图转化为有向图,边数加倍,构造边结构体,没用到邻接矩阵
#include <iostream>
using namespace std;
const int maxNodeNum=110;//最多节点个数
const int maxEdgeNum=10010;//最多边条数
int nodeNum,edgeNum;//节点,有向边个数
int dis[maxNodeNum];//从单源点到各个点的距离
const int inf=0x3f3f3f3f;//边的权重无穷大数
bool loop;//判断是否存在负权回路

struct Edge
{
    int s,e,w;
}edge[maxEdgeNum*2];//构造边,这里因为是无向图,要看成有向处理。

void bellman_ford(int start)
{
    //第一步:赋初值
    for(int i=1;i<=nodeNum;i++)
        dis[i]=inf;
    dis[start]=0;
    //第二步,对边进行松弛更新操作
    for(int i=1;i<=nodeNum-1;i++)//最短路径为简单路径不可能含有环,图中最多有nodeNum-1条边
    {
        bool ok=0;
        for(int j=1;j<=edgeNum;j++)
        {
            if(dis[edge[j].s]+edge[j].w<dis[edge[j].e])//松弛
            {
                dis[edge[j].e]=dis[edge[j].s]+edge[j].w;
                ok=1;
            }
        }
        if(ok==0)
            break;
    }
    //第三步,判断图中是否存在负权环
    loop=0;
    for(int i=1;i<=edgeNum;i++)
        if(dis[edge[i].s]+edge[i].w<dis[edge[i].e])
        loop=1;
}

int main()//125MS
{
    while(cin>>nodeNum>>edgeNum&&(nodeNum||edgeNum))
    {
        int from,to,w;
        int cnt=1;
        for(int i=1;i<=edgeNum;i++)//无向图,一条无向边看为两条有向边
        {
            cin>>from>>to>>w;
            edge[cnt].s=edge[cnt+1].e=from;
            edge[cnt].e=edge[cnt+1].s=to;
            edge[cnt++].w=w;
            edge[cnt++].w=w;//切记,不能写成 edge[cnt++]=edge[cnt++].w;
        }
        edgeNum*=2;//无向图
        bellman_ford(1);
        cout<<dis[nodeNum]<<endl;
    }
    return 0;
}
//SPFA算法,是对bellman_ford算法的优化,采用队列,在队列中取点对其相邻的点进行松弛操作
//如果松弛成功且相邻的点不在队列中,就把相邻的点加入队列,被取的点出队,并把它的状态(是否在队列中)
//改为否,vis[i]=0,同一个节点可以多次进入队列进行松弛操作
//这样的题操作步骤:首先建立邻接矩阵,邻接矩阵初始化为inf,注意需要判断一下输入的边是否小于已有的边,取最小的那个,因为可能有重边,
//建立完邻接矩阵,写SPFA函数,dis[]数组初始化为inf,源点dis[start]=0
#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
const int maxNodeNum=110;//最多节点个数
const int maxEdgeNum=10010;//最多边条数
const int inf=0x3f3f3f3f;//边的权重无穷大数
int nodeNum,edgeNum;//节点,有向边个数
int dis[maxNodeNum];//从单源点到各个点的距离
bool vis[maxNodeNum];//某个节点是否已经在队列中

int mp[maxNodeNum][maxNodeNum];//建立邻接矩阵

void SPFA(int start)
{
    //第一步:建立队列,初始化vis,dis数组,并把源点加入队列中,修改其vis[]状态
    queue<int>q;
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=nodeNum;i++)
        dis[i]=inf;
    dis[start]=0;
    q.push(start);
    vis[start]=1;
    //第二步:在队列中取点,把其vis状态设为0,对该点相邻的点(连接二者的边)进行松弛操作,修改相邻点的dis[]
    //并判断相邻的点vis[]状态是否为0(不存在于队列中),如果是,将其加入到队列中
    while(!q.empty())
    {
        int from=q.front();
        q.pop();
        vis[from]=0;//别忘了这一句,哎
        for(int i=1;i<=nodeNum;i++)
        {
            if(dis[from]+mp[from][i]<dis[i])
            {
                dis[i]=dis[from]+mp[from][i];
                if(!vis[i])//要写在松弛成功的里面
                {
                    q.push(i);
                    vis[i]=1;
                }
            }
        }
    }
}

int main()//109MS
{
    while(cin>>nodeNum>>edgeNum&&(nodeNum||edgeNum))
    {
        int from,to,w;
        memset(mp,inf,sizeof(mp));//初始化
        for(int i=1;i<=edgeNum;i++)//无向图,一条无向边看为两条有向边
        {
            cin>>from>>to>>w;
            if(w<mp[from][to])
                mp[from][to]=mp[to][from]=w;
        }
        SPFA(1);
        cout<<dis[nodeNum]<<endl;
    }
    return 0;
}
//floyed算法,时间复杂度高,但代码简单,可以处理负边,但图中不能包含负权回路
//可以求任意一点到另外一点的最短路,而不只是源点唯一

#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
const int maxNodeNum=110;//最多节点个数
const int maxEdgeNum=10010;//最多边条数
const int inf=0x3f3f3f3f;
int nodeNum,edgeNum;//节点,有向边个数
int mp[maxNodeNum][maxNodeNum];//建立邻接矩阵

void floyed()
{
    for(int k=1;k<=nodeNum;k++)
        for(int i=1;i<=nodeNum;i++)
            for(int j=1;j<=nodeNum;j++)
                if(mp[i][k]+mp[k][j]<mp[i][j])
                    mp[i][j]=mp[i][k]+mp[k][j];
}

int main()//140MS
{
    while(cin>>nodeNum>>edgeNum&&(nodeNum||edgeNum))
    {
        int from,to,w;
        memset(mp,inf,sizeof(mp));//初始化
        for(int i=1;i<=edgeNum;i++)//无向图,一条无向边看为两条有向边
        {
            cin>>from>>to>>w;
            if(w<mp[from][to])
                mp[from][to]=mp[to][from]=w;
        }
        floyed();
        cout<<mp[1][nodeNum]<<endl;
    }
    return 0;
}
//dijkstra算法求最短路,单源最短路,不能处理带有负权的图
//思想为单源点加入集合,更新dis[]数组,每次取dis[]最小的那个点,加入集合,再次更新dis[]数组,取点加入集合,直到所有的点都加入集合中
#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
const int maxNodeNum=110;//最多节点个数
const int maxEdgeNum=10010;//最多边条数
const int inf=0x3f3f3f3f;
int nodeNum,edgeNum;//节点,有向边个数
int mp[maxNodeNum][maxNodeNum];//建立邻接矩阵
int dis[maxNodeNum];//dis[i]为源点到i的最短路径
bool vis[maxNodeNum];//判断某个节点是否已加入集合

void dijkstra(int start)
{
    //**第一步:初始化,dis[]为最大,vis均为0(都未加入集合)
    memset(dis,inf,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[start]=0;
    //**第二步:找dis[]值最小的点,加入集合,并更新与其相连的点的dis[]值

    //一开始集合里没有任何点,下面的循环中,第一个找到的点肯定是源点
    for(int i=1;i<=nodeNum;i++)
    {
        //寻找dis[]最小的点,加入集合中
        int MinNumber,Min=inf;//MinNumber为dis[]值最小的点的编号
        for(int j=1;j<=nodeNum;j++)
        {
            if(dis[j]<Min&&!vis[j])
            {
                Min=dis[j];
                MinNumber=j;
            }
        }
        //找到dis[]最小的点,加入集合,更新与其相连的点的dis值
        vis[MinNumber]=1;
        for(int j=1;j<=nodeNum;j++)
            if(dis[MinNumber]+mp[MinNumber][j]<dis[j])
            dis[j]=dis[MinNumber]+mp[MinNumber][j];
    }
}

int main()//109MS
{
    while(cin>>nodeNum>>edgeNum&&(nodeNum||edgeNum))
    {
        int from,to,w;
        memset(mp,inf,sizeof(mp));//初始化
        for(int i=1;i<=edgeNum;i++)//无向图,一条无向边看为两条有向边
        {
            cin>>from>>to>>w;
            if(w<mp[from][to])
                mp[from][to]=mp[to][from]=w;
        }
        dijkstra(1);
        cout<<dis[nodeNum]<<endl;
    }
    return 0;
}

[ACM] 最短路算法整理(bellman_ford , SPFA , floyed , dijkstra 思想,步骤及模板)

时间: 2024-10-09 16:18:50

[ACM] 最短路算法整理(bellman_ford , SPFA , floyed , dijkstra 思想,步骤及模板)的相关文章

[图论] 最短路径(Bellman-Ford , SPFA , Floyed , Dijkstra)

注:模板以hdu 2544 为例 Problem Description 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗? Input 输入包括多组数据.每组数据第一行是两个整数N.M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路.N=M=

蓝桥杯 最短路 道路和航路 SPFA算法

1.SPFA算法 算法训练 最短路 时间限制:1.0s   内存限制:256.0MB 锦囊1 使用最短路算法. 锦囊2 使用Dijkstra算法,此图的边数比点数的平方要少很多,因此应该使用带堆优化的Dijkstra. 问题描述 给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环).请你计算从1号点到其他点的最短路(顶点从1到n编号). 输入格式 第一行两个整数n, m. 接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边. 输出格式 共n-1行,第i行

算法笔记_071:SPFA算法简单介绍(Java)

目录 1 问题描述 2 解决方案 2.1 具体编码   1 问题描述 何为spfa(Shortest Path Faster Algorithm)算法? spfa算法功能:给定一个加权连通图,选取一个顶点,称为起点,求取起点到其它所有顶点之间的最短距离,其显著特点是可以求含负权图的单源最短路径,且效率较高.(PS:引用自百度百科:spfa是求单源最短路径的一种算法,它还有一个重要的功能是判负环(在差分约束系统中会得以体现),在Bellman-ford算法的基础上加上一个队列优化,减少了冗余的松弛

最短路算法(floyed+Dijkstra+bellman-ford+SPFA)

最短路算法简单模板 一.floyed算法 首先对于floyed算法来说就是最短路径的动态规划解法,时间复杂度为O(n^3) 适用于图中所有点与点之间的最短路径的算法,一般适用于点n较小的情况. Floyed算法有三层循环,循环的层次先后顺序也是比较重要的,分别为k ,i,j:因为dis[k][i][j]代表的是i节点到j节点的最短路如果中间经过节点k的话dis[k][i][j] =dis[k-1][i][k]+dis[k-1][k][j]:否则dis[k][i][j] = dis[k-1][i]

(最短路径算法整理)dijkstra、floyd、bellman-ford、spfa算法模板的整理与介绍

这一篇博客以一些OJ上的题目为载体.整理一下最短路径算法.会陆续的更新... 一.多源最短路算法--floyd算法 floyd算法主要用于求随意两点间的最短路径.也成最短最短路径问题. 核心代码: /** *floyd算法 */ void floyd() { int i, j, k; for (k = 1; k <= n; ++k) {//遍历全部的中间点 for (i = 1; i <= n; ++i) {//遍历全部的起点 for (j = 1; j <= n; ++j) {//遍历

近十年one-to-one最短路算法研究整理【转】

前言:针对单源最短路算法,目前最经典的思路即标号算法,以Dijkstra算法和Bellman-Ford算法为根本演进了各种优化技术和算法.针对复杂网络,传统的优化思路是在数据结构和双向搜索上做文章,或者针对不必要的循环进行排除.近年来,最短路算法大量应用于需要高及时性的领域,比如GIS领域,也大量应用于网络规模巨大的社会网络分析领域,这使得传统思路并不能很好地解决,于是把最短路算法思路本身抽象成两阶段算法,第一阶段为数据预处理,第二阶段为实时地搜索.这二者是互相矛盾的,如何找到平衡是各种算法技术

hdu 4568 spfa 最短路算法+旅行商问题

http://acm.hdu.edu.cn/showproblem.php?pid=4568 Problem Description One day, a hunter named James went to a mysterious area to find the treasures. James wanted to research the area and brought all treasures that he could. The area can be represented a

最短路算法 :Bellman-ford算法 &amp; Dijkstra算法 &amp; floyd算法 &amp; SPFA算法 详解

 本人QQ :2319411771   邮箱 : [email protected] 若您发现本文有什么错误,请联系我,我会及时改正的,谢谢您的合作! 本文为原创文章,转载请注明出处 本文链接   :http://www.cnblogs.com/Yan-C/p/3916281.html . 很早就想写一下最短路的总结了,但是一直懒,就没有写,这几天又在看最短路,岁没什么长进,但还是加深了点理解. 于是就想写一个大点的总结,要写一个全的. 在本文中因为邻接表在比赛中不如前向星好写,而且前向星效率并

最短路算法(dijkstra,bellman_ford,floyd)

最短路算法 dijkstra(初级的最短路算法,适合稠密图,可用邻接表优化) bool relax(int u,int v) { double tmp=max(dist[u],edge[u][v]); if(tmp<dist[v]){ dist[v]=tmp; } } void dijkstra() { memset(vis,0,sizeof(vis)); for(int i=0;i<n;i++){ int x; double mindist=INF; for(int j=0;j<n;j