最短路默写
Time Limit:10000MS Memory Limit:65536K
Total Submit:676 Accepted:396
Case Time Limit:1000MS
Description
有一无负权有向图。求指定两点间的最短路径。
Input
输入:第一行,两个数字n和m,表示n个顶点,m条边
接下来的m行,每行三个整数,分别表示边的起点、终点和边的长度
最后一行 两个整数 x y 表示求从点x到点y的最短路径
Output
输出:一行,一个整数,最短路径长度
Sample Input
3 3
1 2 5
1 3 2
3 2 1
1 2
Sample Output
3
Hint
注:所有数据都不超过100
Source
这里用两种经典且常用方法解决这道题
首先是Dijkstra:
#include<cstdio>
#define inf 999999999
int n,m,Map[101][101];
int dis[101],mark[101];
void dijkstra(int x) //求从x点出发到其他所有点的最短距离
{ ///////////////////初始化///////////////////////////////
int i,j,k,Min;
for(i=1;i<=n;i++) //初始化数据
{
mark[i]=false; //mark记录第i号节点是否被讨论过
dis[i]=Map[x][i]; //初始化dis数组,dis[i]用于记录起点x到点i的最短距离
}
mark[x]=true; //////////////////////算法执行过程////////////////////
do{ //算法主要部分 求x到其他所有点的最短距离和路径
Min=inf; //inf为自定义的常数表示无穷大,比如const int inf=999999999;
k=0; // k记录离x最近的点的编号
for(i=1;i<=n;i++) //寻找当前离x最近且未被讨论过的节点
if (!mark[i]&&dis[i]<Min){Min=dis[i];k=i;}
///////////////////讨论经过k点,有没有其他点到x的距离缩短
if(k>0) //k>0表示找到未被讨论过的节点
{
mark[k]=true; //将k号点设置为已被讨论过
for(i=1;i<=n;i++) //讨论每个点,若起点经k到i的距离更短,则更新dis[i]
if(dis[i]>dis[k]+Map[k][i])dis[i]=dis[k]+Map[k][i];
}
}while(k>0); //若k==0表示全部点都被讨论过了
}
int main(){
int i,j,x,y,z;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
if(i==j)continue;
Map[i][j]=inf;
}
for(i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
Map[x][y]=Map[y][x]=z;
}
scanf("%d%d",&x,&y);
dijkstra(x);
printf("%d",dis[y]);
}
然后是Floyd:
#include<cstdio>
#include<iostream>
#define inf 999999999
using namespace std;
int n,m,s[101][101];
int main(){
scanf("%d%d",&n,&m);
int i,j,k;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i==j)continue;
else s[i][j]=inf;
for(i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
s[x][y]=z;
}
int x,y;
scanf("%d%d",&x,&y);
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
s[i][j]=min(s[i][j],s[i][k]+s[k][j]);
printf("%d",s[x][y]);
}
除了以上两种最短路求法以外,还有Bellman和SPFA等实用的方案,就不一一贴上来了