以杭电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
//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; //<span style="color:#ff0000;">注意不能写vis[start]=1,由于这时候第一个节点还没有被訪问。以下循环中。第一个选择的就是第一个节点,切记</span>
//**第二步:找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 思想,步骤及模板)的更多相关文章

  1. 算法专题 | 10行代码实现的最短路算法——Bellman-ford与SPFA

    今天是算法数据结构专题的第33篇文章,我们一起来聊聊最短路问题. 最短路问题也属于图论算法之一,解决的是在一张有向图当中点与点之间的最短距离问题.最短路算法有很多,比较常用的有bellman-ford ...

  2. 图论最短路径算法总结(Bellman-Ford + SPFA + DAGSP + Dijkstra + Floyd-Warshall)

    这里感谢百度文库,百度百科,维基百科,还有算法导论的作者以及他的小伙伴们...... 最短路是现实生活中很常见的一个问题,之前练习了很多BFS的题目,BFS可以暴力解决很多最短路的问题,但是他有一定的 ...

  3. 图论算法》关于SPFA和Dijkstra算法的两三事

    本来我是想把这两个算法分开写描述的,但是SPFA其实就是Dijkstra的稀疏图优化,所以其实代码差不多,所以就放在一起写了. 因为SPFA是Dijkstra的优化,所以我想来讲讲Dijkstra. ...

  4. poj3259Wormholes (Bellman_Ford/SPFA/Floyed算法判断是否存在负环)

    题目链接:http://poj.org/problem?id=3259 题目大意:一个图,有n个顶点,其中有m条边是双向的且权值为为正,w条边是单向的且权值为负,判断途中是否存在负环,如果有输出YES ...

  5. 10行实现最短路算法——Dijkstra

    今天是算法数据结构专题的第34篇文章,我们来继续聊聊最短路算法. 在上一篇文章当中我们讲解了bellman-ford算法和spfa算法,其中spfa算法是我个人比较常用的算法,比赛当中几乎没有用过其他 ...

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

    目录 1 问题描述 2 解决方案 2.1 具体编码   1 问题描述 何为spfa(Shortest Path Faster Algorithm)算法? spfa算法功能:给定一个加权连通图,选取一个 ...

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

    最短路算法简单模板 一.floyed算法 首先对于floyed算法来说就是最短路径的动态规划解法,时间复杂度为O(n^3) 适用于图中所有点与点之间的最短路径的算法,一般适用于点n较小的情况. Flo ...

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

    前言:针对单源最短路算法,目前最经典的思路即标号算法,以Dijkstra算法和Bellman-Ford算法为根本演进了各种优化技术和算法.针对复杂网络,传统的优化思路是在数据结构和双向搜索上做文章,或 ...

  9. 近十年one-to-one最短路算法研究整理

    前言:针对单源最短路算法,目前最经典的思路即标号算法,以Dijkstra算法和Bellman-Ford算法为根本演进了各种优化技术和算法.针对复杂网络,传统的优化思路是在数据结构和双向搜索上做文章,或 ...

随机推荐

  1. bzoj1001

    平面图求最小割: 其实看bzoj1001一开始着实把我怔住了 AC的人暴多,可自己完全没思路 后来看了某大牛的ppt,才会做 一个月前做这题的吧,今天来简单回忆一下: 首先是欧拉公式 如果一个连通的平 ...

  2. 在try...catch语句中执行Response.End()后如何停止执行catch语句中的内容

    在调用Response.End()时,会执行Thread.CurrentThread.Abort()操作. 如果将Response.End()放在try...catch中,catch会捕捉Thread ...

  3. UVa 10213 (欧拉公式+Java大数) How Many Pieces of Land ?

    题意: 一块圆形土地,在圆周上选n个点,然后两两连线,问把这块土地分成多少块? 分析: 首先紫书上的公式是错的,不过根据书上提供的思路很容易稍加修改得到正确答案! 然后推公式吧,这里用到平面图的欧拉公 ...

  4. vijos1603迷宫

    这题的构思太巧妙了: 经典题目8 给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数mod p的值    把给定的图转为邻接矩阵,即A(i,j)=1当且仅当存在一条边i->j. ...

  5. YQL

    YQL,(Yahoo! Query Language)是一种支持对互联网上的数据进行查询.过滤.连接.类似SQL语法的简单语言.用YQL官方的话:有了YQL,开发人员只需要使用一种 简单的查询语言即可 ...

  6. Linux串口c_cc[VTIME]和c_cc[VMIN]属性设置的作用

    Linux串口c_cc[VTIME]和c_cc[VMIN]属性设置的作用 在串口编程模式下,open未设置O_NONBLOCK或O_NDELAY的情况下. c_cc[VTIME]和c_cc[VMIN] ...

  7. TortoiseGit连接github不用每次输入用户名和密码的方法

    每次git clone 和push 都要输入用户名和密码.虽然安全,但在本机上每次都输有些麻烦,如何记住用户名和密码呢? 当你配置好git后,在C:\Documents and Settings\Ad ...

  8. 积和式Permanent在Mathematica中的运算

    Permanent[m_List] := With[{v = Array[x, Length[m]]}, Coefficient[Times @@ (m.v), Times @@ v]] 参考资料:  ...

  9. hive的使用和深化理解

    1.hive中的数据最终是存放在hdfs上的 2.hive本身不是关系型数据库,hive执行sql语句时会把sql语句翻译成mapreduce程序,然后将mapreduce程序提交到hadoop集群中 ...

  10. viedeo

    http://download.farsight.com.cn/download/Android.htm