最短路径---算法集

  • Dijkstra算法
  • Floyd算法
  • SPFA算法

Dijkstra算法(最经典的单源路径算法-贪心的思想)
问题描述:
数据已在数组中初始化,算出从给定的点到最最终点的一条最短距离。
输出:
最短路径为 16

#include<bits/stdc++.h>
using namespace std;
#define MAXVEX 9
#define M 65535

int p[MAXVEX];//用于存储最短路径下标的数组
int D[MAXVEX];//用于存储到各点最短路径下的权值和

typedef struct{
	int numVertexes;
	int arc[MAXVEX][MAXVEX];
}MGraph;

void ShortestPath_Dijkstra(MGraph G,int v0)
{
	int v,w,k,min;
	int final[MAXVEX];//final[w]==1 表示已经求得顶点V0到Vw的最短路径
	//初始化数据 
	for(v=0;v<G.numVertexes;v++)
	{
		final[v]=0;//全部顶点初始化为未找到最短路径 
		D[v]=G.arc[v0][v];//将于V0点有连线的顶点加上权值 
		p[v]=0;//初始化路径数组P为0 
	}
	D[v0]=0;//v0到v0的路径为0 
	final[v0]=1;//v0到v0不需要求路径
	//开始主循环,每次求得v0到某个v顶点的最短路径
	for(v=1;v<G.numVertexes;v++)
	{
		min=M;
		for(w=0;w<G.numVertexes;w++)
		{
			if(!final[w]&&D[w]<min)
			{
				k=w;//k=8就不再读了
				min=D[w]; 
			}
		}
		cout<<k;
		final[k]=1;//将目前找到的最近的顶点置为1
		//修正当前最短路径及距离
		for(w=0;w<G.numVertexes;w++)
		{
			//如果经过V顶点的路径比现在这条路径的长度短的话,更新!
			if(!final[w]&&(min+G.arc[k][w]<D[w]))
			{
				D[w]=min+G.arc[k][w];//修正当前路径长度
				p[w]=k;
				cout<<"-"<<D[w]; 
			} 
		} 
	} 
	cout<<endl;
}
int main()
{
	MGraph G;
	int i,j;
	G.numVertexes=MAXVEX;
	int a[MAXVEX][MAXVEX]={
	{0,1,5,M,M,M,M,M,M},
	{1,0,3,7,5,M,M,M,M},
	{5,0,3,M,1,7,M,M,M},
	{M,7,M,0,2,M,3,M,M},
	{M,5,1,2,0,3,6,9,M},
	{M,M,7,M,3,0,M,5,M},
	{M,M,M,3,6,M,0,2,7},
	{M,M,M,M,9,5,2,0,4},
	{M,M,M,M,M,M,7,4,0},
	};
	for(i=0;i<MAXVEX;i++)
	   for(j=0;j<MAXVEX;j++)
	       G.arc[i][j]=a[i][j];
	for(i=0;i<MAXVEX;i++)//验证数组中的值
	{
	    for(j=0;j<MAXVEX;j++)
	      cout<<a[i][j]<<" ";
	cout<<endl; 
    }
    ShortestPath_Dijkstra(G,0); 
    cout<<"P的过程为:";//处理过程
	for(i=0;i<MAXVEX;i++)
	{
		if(i==MAXVEX-1)
		  cout<<p[i]<<endl;
		else
		  cout<<p[i]<<"->";
	} 
	cout<<"D的过程为:";
	for(i=0;i<MAXVEX;i++)
	{
		if(i==MAXVEX-1)
		  cout<<D[i]<<endl<<"最短路径为:"<<D[i]<<endl;
		else
		  cout<<D[i]<<"->";
	} 
	return 0;
} 

Floyd算法(经典的多元最短路径算法-动态规划的思想)
问题描述:
数据已在数组中初始化,算出从每个点到最最终点的最短距离。
输出:
0–>8 的最短路径为 16
1–>8 的最短路径为 15
2–>8 的最短路径为 12
3–>8 的最短路径为 9
4–>8 的最短路径为 11
5–>8 的最短路径为 9
6–>8 的最短路径为 6
7–>8 的最短路径为 4

#include<bits/stdc++.h>
using namespace std;
#define MAXVEX 9
#define M 65535

int p[MAXVEX][MAXVEX];//用于存储最短路径下标的数组
int D[MAXVEX][MAXVEX];//用于存储到各点最短路径下的权值和

typedef struct{
	int numVertexes;
	int matrix[MAXVEX][MAXVEX];
}MGraph;

void ShortestPath_Floyd(MGraph G)
{
	int v,w,k;
	//初始化D和p 
	for(v=0;v<G.numVertexes;v++)
	{
		for(w=0;w<G.numVertexes;w++)
		{
		  D[v][w]=G.matrix[v][w];
		  p[v][w]=w;
		}
	}
	//优美的Floyd算法 
	for(k=0;k<G.numVertexes;k++)
		for(v=0;v<G.numVertexes;v++)
		    for(w=0;w<G.numVertexes;w++)
		{
			if(D[v][w]>(D[v][k]+D[k][w]))
			{
				D[v][w]=D[v][k]+D[k][w];
				p[v][w]=p[v][k]; 
			}
		}
}
int main()
{
	MGraph G;
	int i,j;
	G.numVertexes=MAXVEX;
	int a[MAXVEX][MAXVEX]={
	{0,1,5,M,M,M,M,M,M},
	{1,0,3,7,5,M,M,M,M},
	{5,0,3,M,1,7,M,M,M},
	{M,7,M,0,2,M,3,M,M},
	{M,5,1,2,0,3,6,9,M},
	{M,M,7,M,3,0,M,5,M},
	{M,M,M,3,6,M,0,2,7},
	{M,M,M,M,9,5,2,0,4},
	{M,M,M,M,M,M,7,4,0},
	};
	for(i=0;i<MAXVEX;i++)//对二维数组进行赋值 
	   for(j=0;j<MAXVEX;j++)
	       G.matrix[i][j]=a[i][j];
	for(i=0;i<MAXVEX;i++)//测试数据 
	{
	    for(j=0;j<MAXVEX;j++)
	      cout<<a[i][j]<<" ";
	cout<<endl; 
    }
    cout<<"------------------------------"<<endl;
	for(i=0;i<MAXVEX;i++)
	{
		for(j=0;j<MAXVEX;j++)
		    cout<<" "<<G.matrix[i][j];
	    cout<<endl;
	} 
    ShortestPath_Floyd(G); 
	for(i=0;i<G.numVertexes;i++)
	{
		for(j=0;j<G.numVertexes;j++)
		    if(j==G.numVertexes-1)
		       cout<<i<<"-->"<<j<<"的最短路径为"<<D[i][j]<<endl; 
	}
	return 0;
} 

SPAF算法(松弛操作)
问题描述
给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环)。请你计算从1号点到其他点的最短路(顶点从1到n编号)。

输入格式
第一行两个整数n, m。
接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边。

输出格式
共n-1行,第i行表示1号点到i+1号点的最短路。

样例输入
3 3
1 2 -1
2 3 -1
3 1 2
样例输出
-1
-2
数据规模与约定
对于10%的数据,n = 2,m = 2。
对于30%的数据,n <= 5,m <= 10。
对于100%的数据,1 <= n <= 20000,1 <= m <= 200000,-10000 <= l <= 10000,保证从任意顶点都能到达其他所有顶点。

#include <bits/stdc++.h>
using namespace std;

struct edge
{
	int to,val,next;
}e[200100];//e[i].to,e[i].val,e[i].next分别表示第i条边的终点,权值,和另(上)一条于此边相同起点的边的编号
int m,n,head[21000],dis[21000];//head[i]表示当前以i为起点的边的编号,dis[i]表示1号点到i号点的距离
 
void add(int from,int to,int val,int len)//添加边,参数分别代表此边的起点,终点,权值,还有此边的编号
{
	e[len].to=to;
	e[len].val=val;
	e[len].next=head[from];//此边的起点是from,而head[from]保存上一条起点是from的边的编号
	head[from]=len;//添加了这条边后,现在,最新的以from为起点的边编号就是len
}
 
void spfa()
{
	int s;
	queue <int> q;
	int visit[21000];//visit[i]==0代表第i点不在队列中,visit[i]==1代表已在队列中
	for(int i=1;i<=n;i++)
		{
			dis[i]=99999999;
		}//将权值初始化为最大值
	memset(visit,0,sizeof(visit));//初始没有点在队列中
	dis[1]=0;
	q.push(1);
	visit[1]=1;//现在把第一个点扔进队列
	while(!q.empty())//如果队列不空则重复执行以下操作
	{
		int t=q.front();//取队列的第一个元素
		q.pop();
		visit[t]=0;//t现在不在队列里
		for(int i=head[t];i!=-1;i=e[i].next)//枚举所有以t为起点的边
		{
			s=e[i].to;//s为所枚举的边的终点
			if(dis[s]>dis[t]+e[i].val)//尝试松弛s点
			{
				dis[s]=dis[t]+e[i].val;
               {
               	  dis[s]=dis[t]+e[i].val;
			      if(visit[s]==0)
			      {
				      q.push(s);
			       	  visit[s]=1;
			      }//如果成功松弛了s点,把s点扔进队列
               }
		    }
	    }
	}
}

int main ()
{
	cin>>n>>m;
	int from,val,to;
	int len=1;
	memset (head,-1,sizeof(head));
	for(int i=0;i<m;i++)
	{
		cin>>from>>to>>val;
		add(from,to,val,len);
		len++;
	}
	spfa();
	for(int i=2;i<=n;i++)
	{
		cout<<dis[i]<<endl;
	}
}
发布了106 篇原创文章 · 获赞 53 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_43595030/article/details/104080994