几种比较常用的单源(所用点到某一确定点的距离)最短路径的算法有:Dijkstra、Floyd、SPFA、Bellman-ford等。
Floyd算法的思想就是动态规划,用三层循环,来不断的去更新两个点之间的距离,虽然比较简单,但是时间复杂度是O(n^3),适合应用数据比较小的题型。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
using namespace std;
#define Max 10000
int ma[1005][1005];
void floyd(int n){//三种循环遍历一遍
int i, k, j;
for(k = 0; k < n; k++){
for(i = 0; i < n; i++){
for(j = 0; j < n; j++){
ma[i][j] = min(ma[i][j], ma[i][k] + ma[k][j]);
}
}
}
}
int main(){
int n, m;
while(~scanf("%d %d", &n, &m)){
int i, j;
for(i = 0; i < n; i++){
for(j = 0; j < n; j++)
ma[i][j] = Max;
ma[i][i] = 0;
}
for(i = 0; i < m; i++){
int t1, t2, t3;
cin>>t1>>t2>>t3;
if(ma[t1][t2] > t3)
ma[t1][t2] = ma[t2][t1] = t3;
}
floyd(n);
int st, en;
cin>>st>>en;
if(ma[st][en] == Max)cout<<"-1"<<endl;
else cout<<ma[st][en]<<endl;
}
return 0;
}
Dijkstra算法的思想就是用一个先用数组dis去储存所有点到某点m的距离,然后找到最小的一个,再dis更新所有点到最小点的距离加上最小点到m的距离,把已经用到的标记上,证明已经用过了,然后接着找最小的一个。
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
#define INF 0x3f3f3f3f
int ma[300][300];
int dis[300], vis[300];
int n, m;
void Dijkstra(int st){
int i, j;
memset(vis, 0, sizeof(vis));//vis用来标记
for(i = 0; i < n; i++)
dis[i] = ma[st][i];//所用点到初始点m的距离
vis[st] = 1;
dis[st] = 0;
for(i = 1; i < n; i++){//遍历n-1次
int sign, mi = INF;
for(j = 0; j < n; j++){//找到目前
if(dis[j] < mi && !vis[j]){
mi = dis[j];
sign = j;
}
}
vis[sign] = 1;
for(j = 0; j < n; j++){//更新
if(dis[j] > dis[sign] + ma[sign][j])
dis[j] = dis[sign] + ma[sign][j];
}
}
}
int main(){
int i, j;
while(~scanf("%d %d", &n, &m)){
for(i = 0; i < 300; i++){
for(j = 0; j < 300; j++)
ma[i][j] = INF;
ma[i][i] = 0;
}
for(i = 0; i < m ; i++){
int t1, t2, v;
scanf("%d %d %d", &t1, &t2, &v);
if( v < ma[t1][t2])
ma[t1][t2] = ma[t2][t1] = v;
}
int st, en;
scanf("%d %d", &st, &en);
Dijkstra(st);
printf("%d\n",dis[en]==INF?-1:dis[en]);
}
return 0;
}
用优先队列优化:
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
#define Max 1<<30
struct P{
int pos;
int val;
friend bool operator <(P A, P B){//按照从小到大的顺序
return A.val > B.val;
}
};
int ma[1005][1005], dis[1005];
int vis[1005];
int n, m;
void Dijkstra(int st){
priority_queue<P>que;
memset(vis, 0, sizeof(vis));
for(int i = 0; i < n; i++){
dis[i] = Max;
}
dis[st] = 0;//初始点
P f;
f.pos = st, f.val = 0;
que.push(f);//加入队列
while(!que.empty()){
P p = que.top();
que.pop();
int v = p.pos;
if(vis[v])continue;
vis[v] = 1;
for(int i = 0; i < n; i++){//更新
if(!vis[i] && dis[i] > dis[v] + ma[v][i]){
dis[i] = dis[v] + ma[v][i];
P f;
f.pos = i;
f.val = dis[i];
que.push(f);
}
}
}
}
int main(){
while(~scanf("%d %d", &n, &m)){
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++)
ma[i][j] = Max;
ma[i][i] = 0;
}
for(int i = 0; i < m; i++){
int t1, t2, t3;
cin>>t1>>t2>>t3;
if(ma[t1][t2] > t3)
ma[t1][t2] = ma[t2][t1] = t3;
}
int st, en;
cin>>st>>en;
Dijkstra(st);
if(dis[en] == Max)cout<<"-1"<<endl;
else cout<<dis[en]<<endl;
}
return 0;
}
Bellman-ford算法思想就是松弛两点间的距离。进行n-1便对所有点进行松弛。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
using namespace std;
#define Max 1000000
int dis[1005];
struct edge{
int from, to, val;
}e[1005];
int n, m;
void bellman_floyd(int st){
int i, j;
for(i = 0; i < n; i++)dis[i] = Max;
dis[st] = 0;
for(i = 0; i < n; i++){
for(j = 0; j < m; j++){
if(dis[e[j].to] > dis[e[j].from] + e[j].val){
dis[e[j].to] = dis[e[j].from] + e[j].val;
}
if(dis[e[j].from] > dis[e[j].to] + e[j].val){
dis[e[j].from] = dis[e[j].to] + e[j].val;
}
}
}
}
int main(){
while(~scanf("%d %d", &n, &m)){
int i, j;
for(i = 0; i < m; i ++){
int t1, t2, t3;
cin>>t1>>t2>>t3;
e[i].from = t1;
e[i].to = t2;
e[i].val = t3;
}
int st, en;
cin>>st>>en;
bellman_floyd(st);
if(dis[en] == Max)cout<<"-1"<<endl;
else cout<<dis[en]<<endl;
}
return 0;
}
SPFA算法其实就是对Bellman-ford算法的优化,该算法的思想就是从从第一个点开始压出队列,然后跟新到这个压出点的距离,释放这个点,更新的点如果在这个队列里面,就不需要压入,如果没有重新压入。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<queue>
using namespace std;
#define Max 1000000
int dis[1005];
int vis[1005];
int ma[1005][1005];
int n, m;
queue<int>q;
void SPFA(int st)
{
int i, j;
for(i = 0; i < n; i++)
{
dis[i] = Max;
vis[i] = 0;
}
vis[st] = 1;
dis[st] = 0;
q.push(st);
while(!q.empty())
{
int t = q.front();
vis[t] = 1;
q.pop();
for(i = 0; i < n; i++)
{
if(dis[i] > dis[t] + ma[t][i])
{
dis[i] = dis[t] + ma[t][i];
if(!vis[i])
{
vis[i] = 1;
q.push(i);
}
}
}
vis[t] = 0;
}
}
int main()
{
while(~scanf("%d %d", &n, &m))
{
int i, j;
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
ma[i][j] = Max;
ma[i][i] = 0;
}
for(i = 0; i < m; i++)
{
int t1, t2, t3;
cin>>t1>>t2>>t3;
if(ma[t1][t2] > t3)
ma[t1][t2] = ma[t2][t1] = t3;
}
int st, en;
cin>>st>>en;
SPFA(st);
if(dis[en] == Max)cout<<"-1"<<endl;
else cout<<dis[en]<<endl;
}
return 0;
}
优化:使用vector来储存数据
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<vector>
#include<queue>
using namespace std;
#define Max 1000000
int dis[1000], vis[1000];
struct Node
{
int to, val;
} k;
vector<Node>g[1000];
queue<int>q;
int n, m, i, j;
void SPFA(int st)
{
for(i = 0; i < n; i++)
{
dis[i] = Max;
vis[i] = 0;
}
dis[st] = 0;
vis[st] = 1;
q.push(st);
while(!q.empty())
{
int v = q.front();
vis[v] = 1;
q.pop();
for(i = 0; i < g[v].size(); i++)
{
if(dis[g[v][i].to] > dis[v] + g[v][i].val)
{
dis[g[v][i].to] = dis[v] + g[v][i].val;
if(!vis[g[v][i].to])
{
vis[g[v][i].to] = 1;
q.push(g[v][i].to);
}
}
}
vis[v] = 0;
}
}
int main()
{
while(~scanf("%d %d", &n, &m))
{
for(i = 0; i < n; i++)g[i].clear();
int t1, t2, t3;
for(i = 0; i < m; i++)
{
cin>>t1>>t2>>t3;
k.to = t2;
k.val = t3;
g[t1].push_back(k);
k.to = t1;
k.val = t3;
g[t2].push_back(k);
}
int s, t;
cin>>s>>t;
SPFA(s);
if(dis[t] == Max)cout<<"-1"<<endl;
else cout<<dis[t]<<endl;
}
// for(i = 0; i < n; i++)cout<<dis[i]<< " ";
return 0;
}