每日总结 1.31

Floyd-Warshall算法的简单学习

Dijkstra算法的简单学习

首先是Floyd-Warshall算法

了解最短路径的两种基础算法 

1.求一地到另一地的最短路径

法一便是Floyd-Warshall

#include<stdio.h>
int main()
{
	int e[10][10],k,i,j,n,m,t1,t2,t3;
	int inf=99999999;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=n;j++)
		{
			if(i==j)
			{
				e[i][j]=0;
			}
			else
			{
				e[i][j]=inf;
			}
		}
	}
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&t1,&t2,&t3);
		e[t1][t2]=t3;
	}
	//Floyd Warshall核心算法
	for(k=1;k<=n;k++)
	{
		for(i=1;i<=n;i++)
		{
			for(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(i=1;i<=n;i++)
	{
		for(j=1;j<=n;j++)
		{
			printf("%10d",e[i][j]);
		}
		printf("\n");
	}
	return 0;
}

 另一种就是Dijkstra

#include<stdio.h>
int main()
{
	int e[10][10],dis[10],book[10],i,j,n,m,t1,t2,t3,u,v,min;
	int inf=99999999;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=n;j++)
		{
			if(i==j)e[i][j]=0;
			else e[i][j]=inf;
		}
	}
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&t1,&t2,&t3);
		e[t1][t2]=t3;
	}
	for(i=1;i<=n;i++)
	{
		dis[i]=e[1][i];
	}
	for(i=1;i<=n;i++)
	{
		book[i]=0;
	}
	book[1]=1;
	//Dijkstra算法核心
	for(i=1;i<=n-1;i++)
	{
		min=inf;
		for(j=1;j<=n;j++)
		{
			if(book[j]==0&&dis[j]<min)
			{
				min=dis[j];
				u=j;
			}
		}
		book[u]=1;
		for(v=1;v<=n;v++)
		{
			if(e[u][v]<inf)
			{
				if(dis[v]>dis[u]+e[u][v])
				{
					dis[v]=dis[u]+e[u][v];
				}
			}
		}
	}
	for(i=1;i<=n;i++)
	{
		printf("%d ",dis[i]);
	}    
	getchar();
	getchar();
	return 0;
}

Floyd-Warshall的时间复杂度是n的3次方

而Dijkstra的时间复杂度为(M+N)logN相比于前一种更加简便某种意义上更快并且空间复杂度也比较低但是不能解决负权

Bellman-Ford

相比于Floyd算法它时间复杂度于空间复杂度更低

相比于Dijkstra算法它可以解决负权(即一顶点到另外一个顶点的距离为负数)问题

很明显Bellman-Ford解决负权问题即使面对优秀简便的Floyd算法也稍微占上风

个人认为Bellman-Ford算法更适合稀疏图(顶点与边关系为1:1)而其他两种更适合稠密图(顶点与边关系为n:n平方)

其核心代码为
 

for(k=1;k<=n-1;k++)//核心语句
{
	for(i=1;i<=m;i++)
	{
		if(dis[v[i]]>dis[u[i]]+w[i])
		{
			dis[v[i]]=dis[u[i]]+w[i];
		}
	}
}

核心思想即在总共n-1轮中,从一个顶点到另一个顶点由只经过一条边到经过n-1条边进行不断筛选选出到达各个顶点的最短路径,而整个逻辑最多执行n-1轮,所以该算法可以简单优化,即加入一个数组在每一次更新中cheak是否dis数组有更新,即没有更新即没有更优方案(可以仔细想一想该算法的核心)

优化后的代码如下
 

for(k=1;k<=n-1;k++)//核心语句
	{
		for(i=1;i<=n;i++)
		{
			bak[i]=dis[i];
		}
		for(i=1;i<=m;i++)
		{
			if(dis[v[i]]>dis[u[i]]+w[i])
			{
				dis[v[i]]=dis[u[i]]+w[i];
			}
		}
		//小优化,也许不需要完整循环n-1次
		check=0;
		for(i=1;i<=n;i++)
		{
			if(bak[i]!=dis[i])
			{
				check=1;
				break;
			}
		}
    }

Bellman-Ford基础思想已经解决

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值