图论--最短路

最短路

最短路问题分为多源最短路(求两点之间的最短路)单源最短路(求所有点到某特定点的最短距离)。感觉和前面的最小生成树的感觉差不多,但是相比还是复杂一点(算法也多)。

算法:

Dijkstra算法

不带负权的有向或者无向图

如何实现这个算法

  1. 首先找到一点其边最小
  2. 然后以这个为中间,往外扩到两家连接起来(扩展的时候找最小的最大的(根据题目要求))
    代码:
priority_queue<pair<int,int>>q;
//大根堆(优先队列),pair的二维为结点编号
//pair的第一维为dist的相反数(利用相反数变成小根堆)
void dijkstra()
{
	memset(d,0x3f,sizeof(d));
	memset(v,0,sizeof(v));  //结点进行标记
	d[1]=0;
	q.push(make_pair(0,1);
	while(q.size())
	{
		int x=q.top().second;q,pop();  //取出堆顶
		if(v[x]) continue;
		v[x]=1;
		for(int i=head[x];i;i=Next[i])  //扫描出边数
		{
		int y=ver[i],z=edge[i];
		if(d[y]>d[x]+z)
		{
		d[y]=d[x]+z;
		q.push(make_pair(-d[y],y);)   //元素插入堆
			}
		}
	}
}

Folyd算法及求解最小环

正、负权的有向或者无向图都可,但是不可以有负环
可以求出每对点之间的最短距离

如何实现这个算法
运用到动态规划的知识!!(博客主的动态规划讲解)就是进行枚举进行比较和和实验。
代码:

for(k=1;k<=n;k++)  //枚举中点
for(i=1;i<=n;i++)   //枚举起点
for(j=1;j<=n;j++)   //枚举终点
if((a[i][k]!=INF)&&(d[k][j]!=INF)&&(d[i][k]+d[k][j]<d[i][j]))
d[i][j]=d[i][k]+d[k][j];

Bellman-Ford算法

求解单源点最短路问题,正负权边都可以进行

如何实现这个算法

  • 首先对所有顶点的最短距离进行估值
  • 同样的使每个顶点之间的距离都逼近最小
  • 检查负权回路:
    判断边两端是否收敛。如果未收敛的顶点,则返回false;否则返回true,并且从源点可达的顶点最短距离保存在d[v]。

代码:

bool bellman(int v0)
{
	int i,j;
	for(i=1;i<=nv;i++) d[i]=maxx;
	d[v0]=0;
	for(i=1;i<=nv-1;i++)   
	for(j=1;j<=ne;j++)
	if(d[edge[j].a+edge[j].w]<d[edge[j].b])//进行比较出最小的那个边
	d[edge[j].b]=edge[j].w+d[edge[j].a]; //加入其中
	for(j=1;j<=ne;j++)
	if(d[edge[j].a]+edge[j].w<d[edge[j].b]) return false;  //负权返回
	return true;
	}

SPFA算法

可以判断负环(如果某个点弹出队列的次数超过n-1次,则是负环),但是对于存在负环的图,无法计算单源最短路。
如何实现这个算法

  • 初始化,然后对进入的点进行标记
  • 从队首中取出一个点i,标记i已经出队,接着对与i点有边相连的j点进行松弛操作,如果松弛成功,则对j入队的次数进行检查,如果大于等于n,说明出现负环,算法结束。否则改进dist[j]的值,再检查j是否在队列中,如果不在,就将j点加入队尾。

代码:

void spaf()
{      //s为源点,vst[]记录点是否在队列中,距离值为dist[];
	memset(d,0x3f,sizeof(d));
	memset(v,0,sizeof(v));
	d[1]=0;v[1]=1;
	q.push(1);
	while(q,size())
	{
		intx=q.front();q.pop();
		v[x]=0;
		for(int i=head[x];i;i=Next[i])
		{
			int y=ver[i].z=edge[i];
			if(d[y]>d[x]+z)
			{
				d[y]=d[x]+z;
				if(!v[y])q.push(y),v[y]=1;
			}
		}
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值