8.7 浅析图论最短路算法

个人比较喜欢,dijkstra和spfa

首先,存图方式有很多,个人喜欢链式前向星线性存图

flyod:

这个算法的复杂度是O(n^3),在竞赛中,一般超过一亿的算法就要谨慎,所以,这个可以在n<500的时候用。

1 注意判断重边。

2 注意赋值f[i][i]=0。

3 使用时注意条件。

if(dp[i][k]!=1e9&&dp[k][j]!=1e9)不加这一句的话会莫名其妙出错

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long u,v,w,n,m;
long long dp[1505][1505];
int main()
{
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			dp[i][j]=1e9;
		}
	}
	for(int i=1;i<=n;i++) dp[i][i]=0;
	for(int i=1;i<=m;i++)
	{
		scanf("%lld%lld%lld",&u,&v,&w);
		dp[u][v]=min(dp[u][v],w);
	}
	for(int k=1;k<=n;k++)
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				if(dp[i][k]!=1e9&&dp[k][j]!=1e9)
				dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
			}
		}
	}
	if(dp[1][n]==1e9) printf("-1");
	else printf("%lld",dp[1][n]);
	
	return 0;
}

 spfa:

不用判断重边

个人认为还是一样的思想,枚举中间节点

注意vis数组表示当前这个点有没有在队列内,如果不在,再进行最短路的查找

有缺点就是容易被卡,俗话说的好“spfa它已经死了”,(主要是因为时间复杂度过高),需要跑很多遍错误的前置答案

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int Maxn=2e3+5;
struct egde{
	int to,next,val;
}e[50*Maxn];
queue<int> q;
int n,m,tot;
int head[Maxn],dis[Maxn];
bool vis[Maxn];
inline void add(int u,int v,int w)
{
	e[++tot].to=v;
	e[tot].next=head[u];
	e[tot].val=w;
	head[u]=tot;
}
inline void spfa(int st)
{
	for(int i=1;i<=n;i++)
	{
		dis[i]=1e9;
	}
	dis[st]=0;vis[st]=1;
	q.push(st);
	while(!q.empty())
	{
		int now=q.front();
		q.pop();vis[now]=0;
		for(int i=head[now];i;i=e[i].next)
		{
			int nx=e[i].to;
			if(dis[nx]>dis[now]+e[i].val)
			{
				dis[nx]=dis[now]+e[i].val;
				if(vis[nx]==0)
				{
					vis[nx]=1;
					q.push(nx);
				}
			}
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1,u,v,w;i<=m;i++)
	{
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);
	}
	spfa(1);
	if(dis[n]==1e9) printf("-1");
	else printf("%d",dis[n]);
	
	return 0;
}

dijstra:

不用判断重边,但尤其注意不能有负边,一定注意。

时间复杂度低,主要用贪心的想法,可以用堆优化,还是用上为好

//xian-gaoxinyizhong-崔卓
//T3
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std; 
const int Maxn=5e5;
struct egde{
	int to,val,next;
}e[2*Maxn];
struct node{
	int dis,num;
	friend bool operator <(node x,node y)
	{
		return x.dis<y.dis;
	}
}now;
priority_queue<node> q;
int n,m,tot;
int head[Maxn],dis[Maxn];
bool vis[Maxn];
inline void add(int u,int v,int w)
{
	e[++tot].to=v;
	e[tot].val=w;
	e[tot].next=head[u];
	head[u]=tot;
}
inline void dj()
{
	for(int i=1;i<=n;i++)
	{
		dis[i]=1e9;
	}
	dis[1]=0;
	now.dis=0;now.num=1;
	q.push(now);
	while(!q.empty())
	{
		now=q.top();q.pop();
		if(vis[now.num]==0)
		{
			vis[now.num]=1;
			for(int i=head[now.num];i;i=e[i].next)
			{
				if(dis[e[i].to]>dis[now.num]+e[i].val)
				{
					dis[e[i].to]=dis[now.num]+e[i].val;
					if(vis[e[i].to]==0)
					{
						q.push((node){dis[e[i].to],e[i].to});
					}
				}
			}
		}
	}
	
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1,u,v,w;i<=m;i++)
	{
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);
	}
	dj();
	if(dis[n]==-1e9)
	{
		printf("-1");
	}
	else printf("%d ",dis[n]);
	
	return 0;
}
/*
7 7
1 2 1
2 5 1
2 3 1
3 6 1
3 4 1
4 7 1
2 7 1
*/

以上都要注意一个问题,开数组的时候,边和点的大小分开开,要不会炸

上一篇:回文自动机学习笔记


下一篇:Codeforces Global Round 16 E-Buds Re-hanging 树上搜索/树上dp