HDU - 2544 最短路模板(floyd dijkstra SPFA 邻接矩阵 邻接表 链式前向星)

GDUT 2020寒假训练 图论专题 B

原题链接

题目

原题截图
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
对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间

样例
input
2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0
output
3
2

最短路的模板题

floyd
floyd模板直接套上去。
用三角形思想好理解一点。

代码
#include<iostream>
#include<cstdio>
#include<memory.h>
#include<algorithm>
using namespace std;
long long  mp[105][105];
int main()
{
	int n,m;
	while(cin>>n>>m&&n!=0)
	{
		memset(mp,0x3f,sizeof mp);//初始化地图的两点间距离都为最大值
		for(int i=1;i<=m;i++)
		{
			int x,y;
			long long w;
			cin>>x>>y>>w;
			mp[x][y]=mp[y][x]=min(mp[x][y],w);//无向图 x->y和y->x都要更新,且保证数据是最小的			
		}
		int st=1,ed=n;
		for(int k=1;k<=n;k++)
		{
			for(int i=1;i<=n;i++)
			{
				for(int j=1;j<=n;j++)
				{
					mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);//dp思想 松弛操作 
				}
			}
		}
		cout<<mp[st][ed]<<endl;
	}
	
	return 0;
} 

dijkstra
dijkstra的思想是广搜+贪心,就是先找到当前点距离起点最近的一个点(这里是贪心思想),然后用这个点去更新与他相连的所有点(广搜),因为每一次都是找当前可以用来更新的点的最小距离,也就是每一次都用到起点最近的点去更新,那么到最后的距离一定是各个点到起点的最短距离。
朴素算法的dijkstra是朴素的寻找最小值

邻接矩阵+朴素贪心
//dijkstra-邻接矩阵+朴素贪心 
#include<iostream>
#include<cstdio>
#include<memory.h>
#include<algorithm>
using namespace std;
long long mp[105][105];
bool vis[105];
long long dis[105];//从该点到起点的最短距离 
int main()
{
	int n,m;
	while(cin>>n>>m&&n!=0)
	{
		memset(vis,false,sizeof vis);//初始化全部没有访问到
		memset(dis,0x3f,sizeof dis);//初始化距离为无穷大(这里0x3f3f3f3f满足两个无穷大相加还是无穷大不会溢出) 
		memset(mp,0x3f,sizeof mp);
		for(int i=1;i<=m;i++)
		{
			int x,y;
			long long w;
			cin>>x>>y>>w;
			mp[x][y]=mp[y][x]=min(mp[x][y],w);//无向图 x->y和y->x都要更新,且保证数据是最小的 
		}
		int st=1;
		int ed=n;
		dis[st]=0;
		for(int i=1;i<=n;i++)//计数,只要每个点都访问一遍就可以找到最小值 
		{
			/*以下过程在贪心,找到dis数组中距离起点最小的点进行更新*/
			long long minn=0x3f3f3f3f,minx;//minn为当前的最小值 minx为当前最小值所对应的点
			for(int j=1;j<=n;j++)
			{
				if(vis[j]==false&&dis[j]<minn)
				{
					minn=dis[j];
					minx=j;
				}
			} 
			/*找到了最小的点,利用最小的点搭桥,更新其他的点*/
			vis[minx]=true;
			for(int j=1;j<=n;j++)
			{
				if(vis[j]==false)
				{
					dis[j]=min(dis[j],minn+mp[minx][j]);
				}
			}
		}
		cout<<dis[ed]<<endl;//输出终点到起点的距离 
	}
	
	return 0;
}
邻接矩阵+优先队列优化

因为在贪心寻找最小值的的时候要遍历所有点,那么会带来一个n的时间复杂度,使用优先队列进行优化,可以将n缩小到logn
顺便,实现了一下重载运算符

//dijkstra-邻接矩阵+优先队列优化 
#include<iostream>
#include<cstdio>
#include<memory.h>
#include<algorithm>
#include<queue>
using namespace std;
long long mp[105][105];
bool vis[105];
//long long dis[105];
struct NODE{
	int x;
	long long w;
	bool operator < (const NODE &n) const
	{
		return w<n.w;
	}
};
long long dis[105];//从该点到起点的最短距离 
priority_queue<NODE> open;
int main()
{
	int n,m;
	while(cin>>n>>m&&n!=0)
	{
		memset(vis,false,sizeof vis);//初始化全部没有访问到
		memset(dis,0x3f,sizeof dis);//初始化距离为无穷大(这里0x3f3f3f3f满足两个无穷大相加还是无穷大不会溢出) 
		memset(mp,0x3f,sizeof mp);
		for(int i=1;i<=m;i++)
		{
			int x,y;
			long long w;
			cin>>x>>y>>w;
			mp[x][y]=mp[y][x]=min(mp[x][y],w);//无向图 x->y和y->x都要更新,且保证数据是最小的 
		}
		NODE st;
		st.x=1;
		st.w=dis[st.x]=0;
		open.push(st);
		while(!open.empty())
		{
			NODE noww=open.top();//直接找到当前距离起点最近的点 
			NODE temp;
			open.pop();
			if(vis[noww.x]==true)continue;//拿来更新其他店的点不必再进行一次更新 
			vis[noww.x]=true;
			for(int i=1;i<=n;i++)//广搜思想搜索与之相连的点
			{
				if(dis[i]>dis[noww.x]+mp[noww.x][i])//相连的点是否有必要更新 
				{
					dis[i]=dis[noww.x]+mp[noww.x][i];
					vis[i]=false; //已经被更新了最小值,可以重新用他来更新其他店的最小值所以置为未访问 
					temp.x=i;
					temp.w=dis[i];
					open.push(temp);
				}
			}
		}
		cout<<dis[n]<<endl;
	}
	
	return 0;
}
邻接表+优先队列

链式前向星+优先队列

SPFA

发布了21 篇原创文章 · 获赞 1 · 访问量 417

猜你喜欢

转载自blog.csdn.net/xcy2001/article/details/104519499