贪心算法---最短路径(Dijkstra算法)---一场说走就走的旅行

#include<bits/stdc++.h>
using namespace std;
const int N=100;//城市的个数可修改
const int INF=1e7;//初始化无穷大为10000000
int mp[100][100];//,dist[N],p[N],n,m;//n为城市的个数,m为城市间路线的条数
int dist[N],p[N],n,m;
bool flag[N];//如果flag[i]等于true,说明顶点i已经加入到集合S;否则顶点i属于集合V-S.

void Dijkstra(int u)
{
	for(int i=1;i<=n;i++)
	{
		dist[i]=mp[u][i];//初始化源点u到其他各个顶点的最短路径长度。
		flag[i]=false;
		if(dist[i]==INF)
		  p[i]=-1;
		else
		  p[i]=u; 
	}
	dist[u]=0;
	flag[u]=true;//初始时,集合s中只有一个元素:源点u。 
	for(int i=1;i<=n;i++)
	{
		int temp=INF,t=u;
		for(int j=1;j<=n;j++)//在集合V-S中寻找距离源点u最近的顶点t。 
		   if(!flag[j]&&dist[j]<temp)
		   {
		   	t=j;
		   	temp=dist[j];
		   }
		if(t==u) return ;//找不到t,跳出循环。 
		flag[t]=true;//否则,将t加入集合。
		for(int j=1;j<=n;j++)//更新集合V-S中与t邻接的顶点到源点u的距离 
		   if(!flag[j]&&mp[t][i]<INF)//!flag[j]表示j在V-S中 
		     if(dist[j]>(dist[t]+mp[t][i]))
			 {
			 	dist[j]=dist[t]+mp[t][i];
			 	p[j]=t;
			 }
	}
} 
int main()
{
	int u,v,w,st;
	cout<<"请输入城市的个数:"<<endl;
	cin>>n;
	cout<<"请输入城市之间的路线的个数:"<<endl;
	cin>>m;
	cout<<"请输入城市之间的路线及距离:"<<endl;
	for(int i=1;i<=n;i++)//初始化图的邻接矩阵 
	   for(int j=1;j<=n;j++)
	       mp[i][j]=INF;//初始化邻接矩阵为无穷大
	while(m--)
	{
		cin>>u>>v>>w;
		mp[u][v]=min(mp[u][v],w);//邻接矩阵储存,保留最小的距离。 
	}
	cout<<"请输入小明所在的位置:"<<endl;
	cin>>st;
	Dijkstra(st);
	cout<<"小明所在的位置:"<<st<<endl;
	for(int i=1;i<=n;i++)
	{
		 cout<<"小明:"<<st<<"-"<<"要去的位置:"<<i<<endl;
	if(dist[i]==INF)
	   cout<<"sorry,无路可达"<<endl;
	else
	   cout<<"最短距离为:"<<dist[i]<<endl;
	}
	return 0;
} 

第一次优化处理:增添
因为在程序中使用p[ ]数组记录了最短路往上每一个结点的前驱,因此除了显示最短路径外,还可以显示最短路往上经过了哪些城市,可以增加一段程序逆向找到该最短路往上的城市序列。

#include<bits/stdc++.h>
using namespace std;
const int N=100;//城市的个数可修改
const int INF=1e7;//初始化无穷大为10000000
int mp[100][100];//,dist[N],p[N],n,m;//n为城市的个数,m为城市间路线的条数
int dist[N],p[N],n,m;
bool flag[N];//如果flag[i]等于true,说明顶点i已经加入到集合S;否则顶点i属于集合V-S.

void Dijkstra(int u)
{
	for(int i=1;i<=n;i++)
	{
		dist[i]=mp[u][i];//初始化源点u到其他各个顶点的最短路径长度。
		flag[i]=false;
		if(dist[i]==INF)
		  p[i]=-1;
		else
		  p[i]=u; 
	}
	dist[u]=0;
	flag[u]=true;//初始时,集合s中只有一个元素:源点u。 
	for(int i=1;i<=n;i++)
	{
		int temp=INF,t=u;
		for(int j=1;j<=n;j++)//在集合V-S中寻找距离源点u最近的顶点t。 
		   if(!flag[j]&&dist[j]<temp)
		   {
		   	t=j;
		   	temp=dist[j];
		   }
		if(t==u) return ;//找不到t,跳出循环。 
		flag[t]=true;//否则,将t加入集合。
		for(int j=1;j<=n;j++)//更新集合V-S中与t邻接的顶点到源点u的距离 
		   if(!flag[j]&&mp[t][j]<INF)//!flag[j]表示j在V-S中 
		     if(dist[j]>(dist[t]+mp[t][j]))
			 {
			 	dist[j]=dist[t]+mp[t][j];
			 	p[j]=t;
			 }
	}
} 
void findpath(int u)
{
	int x;
	stack<int>s;//利用C++自带的函数创建一个栈s,需要程序头部引用#include<stack>
	cout<<"源点为:"<<u<<endl;
	for(int i=1;i<=n;i++)
	{
		x=p[i];
		while(x!=-1)
		{
			s.push(x);
			x=p[x]; 
		}
		cout<<"源点到其他各顶点最短路径为:"; 
		while(!s.empty())
		{
			cout<<s.top()<<"--";//依次取栈顶元素
			s.pop();//出栈 
		} 
		cout<<i<<";最短距离为:"<<dist[i]<<endl;
	} 
}
int main()
{
	int u,v,w,st;
	cout<<"请输入城市的个数:"<<endl;
	cin>>n;
	cout<<"请输入城市之间的路线的个数:"<<endl;
	cin>>m;
	cout<<"请输入城市之间的路线及距离:"<<endl;
	for(int i=1;i<=n;i++)//初始化图的邻接矩阵 
	   for(int j=1;j<=n;j++)
	       mp[i][j]=INF;//初始化邻接矩阵为无穷大
	while(m--)
	{
		cin>>u>>v>>w;
		mp[u][v]=min(mp[u][v],w);//邻接矩阵储存,保留最小的距离。 
	}
	cout<<"请输入小明所在的位置:"<<endl;
	cin>>st;
	Dijkstra(st);
	cout<<"小明所在的位置:"<<st<<endl;
	for(int i=1;i<=n;i++)
	{
		 cout<<"小明:"<<st<<"-"<<"要去的位置:"<<i<<endl;
	if(dist[i]==INF)
	   cout<<"sorry,无路可达"<<endl;
	else
	   cout<<"最短距离为:"<<dist[i]<<endl;
	}
	findpath(st);
	return 0;
} 

第二次优化处理:使用优先队列优化Dijkstra算法

#include<bits/stdc++.h>
using namespace std;
const int N=100;//城市的个数可修改
const int INF=1e7;//初始化无穷大为10000000
int mp[100][100];//,dist[N],p[N],n,m;//n为城市的个数,m为城市间路线的条数
int dist[N],p[N],n,m;
int flag[N];//如果flag[i]等于true,说明顶点i已经加入到集合S;否则顶点i属于集合V-S

struct Node{
	int u,step;//u为顶点,step为源点到顶点u的最短路径
	Node(){};
	Node(int a,int sp){
		u=a;//参数传递,u为顶点 
		step=sp;//参数传递,step为源点到顶点u的最短路径 
	} 
	bool operator<(const Node &a)const{
	      return step>a.step;//重载<,step(源点到顶点u的最短路径)最小值优先 
	} 
};

void Dijkstra(int st)
{
	priority_queue<Node>Q;//优先队列优化
	Q.push(Node(st,0));
	memset(flag,0,sizeof(flag));//初始化flag数组为0 
	for(int i=1;i<=n;i++)
		dist[i]=INF; //初始化所有距离为无穷大 
	dist[st]=0;
	while(!Q.empty())
	{
		Node it=Q.top();//优先队列队头元素为最小值
		Q.pop();
		int t=it.u;
		if(flag[t])//说明已经找到了最短距离,该结点是队列里面的重复元素
			continue;
		flag[t]=1; 
	for(int i=1;i<=n;i++)
	  {
		if(!flag[i]&&mp[t][i]<INF)//判断与当前点有关系的点,并且自己不可找到自己 
		   {
		   	if(dist[i]>dist[t]+mp[t][i])//求距离当前点的每个点的最短距离,进行松弛操作 
			   {
			   	dist[i]=dist[t]+mp[t][i];
			   	Q.push(Node(i,dist[i]));//把更新后的最短距离压入优先队列(注意里面的元素有重复!) 
			   } 
	       }
	  }
	} 
}
int main()
{
	int u,v,w,st;
	cout<<"请输入城市的个数:"<<endl;
	cin>>n;
	cout<<"请输入城市之间的路线的个数:"<<endl;
	cin>>m;
	cout<<"请输入城市之间的路线及距离:"<<endl;
	for(int i=1;i<=n;i++)//初始化图的邻接矩阵 
	   for(int j=1;j<=n;j++)
	       mp[i][j]=INF;//初始化邻接矩阵为无穷大
	while(m--)
	{
		cin>>u>>v>>w;
		mp[u][v]=min(mp[u][v],w);//邻接矩阵储存,保留最小的距离。 
	}
	cout<<"请输入小明所在的位置:"<<endl;
	cin>>st;
	Dijkstra(st);
	cout<<"小明所在的位置:"<<st<<endl;
	for(int i=1;i<=n;i++)
	{
		 cout<<"小明:"<<st<<"-"<<"要去的位置:"<<i<<endl;
	if(dist[i]==INF)
	   cout<<"sorry,无路可达"<<endl;
	else
	   cout<<"最短距离为:"<<dist[i]<<endl;
	}
	return 0;
} 
发布了106 篇原创文章 · 获赞 53 · 访问量 2万+

猜你喜欢

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