对最短路算法的总结

 

一些最短路的题目

总结一下spfa算法和dj算法区别
首先
1:dj算法开始的book都是0,而且当找到一个最小点,接下来松弛的操作,只是入队,而不将他们的book数组改变,改变book数组只在找到最小点的时候这一次而已
2;spfa算法不同,spfa其实就是bellman算法的强化版,他是现将起始点入队并且入队的标志就是book数组变为1,-----重点就是入队操作与book数组改变的操作一致----,队头元素对接下来的元素进行松
弛,如果找到一个,入队并且打上标志,-------再次申明,打上标志跟入队操作一致,出队也是一样!! 

一道题目用spfa与dj算法来解此题的逆向思维很厉害,需要1到其她点的最短路,也需要其他点到1的最短路,而第二部只需要将所有点反过来再跑一边最短路即可

dj算法-用优先队列优化

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int  maxn=2e4+10;
const int maxx=6e4+10;
int book[maxn];
int n,m;;
ll head[maxx],dist[maxn],cnt=0;
struct node
{
	int to,next;
	ll w;
} edge[maxx];
struct data
{
	int x1,x2;
	ll x3;
} a[maxx];
void add(int u,int v,ll z)
{
	edge[cnt].to=v;
	edge[cnt].w=z;
	edge[cnt].next=head[u];
	head[u]=cnt++;
}

void dj(int s)
{
	for(int i=1; i<=n; i++)
	{
		book[i]=0;
		dist[i]=INF;
	}
	dist[s]=0;
	//距离+顶点
	priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > >q;
	q.push(make_pair(0,s));
	while(!q.empty())
	{

		int f=q.top().second;q.pop();
		
		if(book[f])continue;
		
		book[f]=1;
		for(int i=head[f]; i!=-1; i=edge[i].next)
		{
			if(dist[edge[i].to]>dist[f]+edge[i].w&&!book[edge[i].to])
			{
				dist[edge[i].to]=dist[f]+edge[i].w;
				
			//	book[edge[i].to]=1;
				q.push(make_pair(dist[edge[i].to],edge[i].to));

			}
		}
	}
}


int main()
{

	int T;
	ios::sync_with_stdio(false);
	cin>>T;
	while(T--)
	{

		ll sum=0;
		cnt=0;
		cin>>n>>m;
		for(int i=1; i<=n; i++)
			head[i]=-1;
		for(int i=0; i<m; i++)
		{
			cin>>a[i].x1>>a[i].x2>>a[i].x3;
			add(a[i].x1,a[i].x2,a[i].x3);
		}
		dj(1);
		for(int i=1; i<=n; i++)
			sum+=dist[i];
			//cout<<sum<<"-------------"<<endl;
		cnt=0;
		for(int i=1; i<=n; i++)
			head[i]=-1;
		for(int i=0; i<m; i++)add(a[i].x2,a[i].x1,a[i].x3);
		dj(1);
		for(int i=1; i<=n; i++)
			sum+=dist[i];
		cout<<sum<<endl;
	}
	return 0;
}

spfa算法

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int maxn=2e4+10;
const int maxm=6e4+10;
int head[maxn],cnt,from[maxm],to[maxm];
int n,m;
bool vis[maxn];
ll dis[maxn],cost[maxm];
struct Edge
{
	int u,v,next;
	ll w;
} edge[maxm];
void addedge(int u,int v,ll w)
{
	edge[cnt].u=u;
	edge[cnt].v=v;
	edge[cnt].w=w;
	edge[cnt].next=head[u];
	head[u]=cnt++;
}
void spfa(int s)
{
	for(int i=1; i<=n; i++)
	{
		vis[i]=false;
		dis[i]=inf;
	}

	queue<int> q;
	q.push(s);
	dis[s]=0;
	vis[s]=true;
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		vis[u]=false;
		for(int i=head[u]; i!=-1; i=edge[i].next)
		{
			if(dis[edge[i].v]>dis[u]+edge[i].w)
			{
				dis[edge[i].v]=dis[u]+edge[i].w;
				if(!vis[edge[i].v])
				{
					vis[edge[i].v]=true;
					q.push(edge[i].v);
				}
			}
		}
	}
}
int main()
{
	int T;
	ios::sync_with_stdio(false);
	cin>>T;
	while(T--)
	{
		cnt=0;
		cin>>n>>m;
		for(int i=1; i<=n; i++)
			head[i]=-1;
		for(int i=1; i<=m; i++)
		{
			cin>>from[i]>>to[i]>>cost[i];
			addedge(from[i],to[i],cost[i]);
		}
		spfa(1);
		ll ans=0;
		for(int i=1; i<=n; i++)
			ans+=dis[i];
		cnt=0;
		for(int i=1; i<=n; i++)
			head[i]=-1;
		for(int i=1; i<=m; i++)
			addedge(to[i],from[i],cost[i]);
		spfa(1);
		for(int i=1; i<=n; i++)
			ans+=dis[i];
		cout<<ans<<endl;
	}
	return 0;
}

 spfa朴素算法,检查是否有回路

#include<bits/stdc++.h>
using namespace std;
const int inf=999999;



int main()
{
	int dis[10],u[10],v[10],w[10],check,flag,n,m;
	cin>>n>>m;//n个顶点,m条边
	for(int i=1; i<=m; i++)
		cin>>u[i]>>v[i]>>w[i];
	for(int i=1; i<=n; i++)
		dis[i]=inf;
	dis[1]=0;
	for(int k=1; k<=n-1; i++)//最多进行n-1个阶段 
	{
		check=0;
		for(int i=1; i<=m; i++)//对每条边进行松弛操作 
			if(dis[v[i]]>dis[u[i]]+w[i])
			{
				dis[v[i]]=dis[u[i]]+w[i];
				check=1;
			}
		if(check==0)break;//如果此次一次松弛操作也没进行就返回,因为此时dis已经达到极致 
	}
	flag=0;
	for(int i=1; i<=n; i++)
		if(dis[v[i]]>dis[u[i]]+w[i])flag=1;
	if(flag==1)cout<<"此图含有负权回路";
	else for(int i=1; i<=n; i++)
			cout<<dis[i]<<" ";

	return 0;
}

Floyd算法---多源最短路

#include<bits/stdc++.h>
using namespace std;
const int inf=999999;
int main()
{
	int e[10][10],k,n,m,t1,t2,t3;
	    cin>>n>>m;
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n; j++)
			if(i==j)e[i][j]=0;
			else e[i][j]=inf;
	for(int i=1; i<=m; i++)
	{
		cin>>t1>>t2>>t3;
		e[t1][t2]=t3;
	}
//Floyd核心思想,用到了动态规划的思想,后面的可以用到前面的最小值,e[i][j]>e[i][k]+e[k][j] ,这样最多更新n次 
//这为后面spfa算法做了铺垫	
	for(int k=1; k<=n; k++)
		for(int i=1; i<=n; i++)
			for(int j=1; j<=n; j++)
				if(e[i][j]>e[i][k]+e[k][j])e[i][j]=e[i][k]+e[k][j];
	for(int i=1; i<=n; i++)
	{
		for(int j=1; j<=n; j++)cout<<e[i][j]<<" ";
		cout<<endl;
	}
	return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值