7-5 地铁一日游(Floyd 算法)

本文详细解读了Floyd算法,通过实例演示如何利用三层循环更新邻接矩阵,实现从任意两点之间的最短路径查找。通过山西青岛路线示例,介绍了算法核心思想并展示了代码实现,包括输入处理、矩阵构建和深度优先遍历应用。
摘要由CSDN通过智能技术生成

关于这道题有一点多元所以我们很多人都理解不了,这道题的关键就是这个Floyd 算法这个算法我们,这个算法其实很简单滴,就是有三层循环,第一次循环作为中心结点,后两次循环就是遍历结点了。

 

具体就看每一点都可以通过其他点为媒介到达,所以我们这个算法就是将每一个点到其他的点的最短距离保存下来,以动态规划为基础的一个算法。就比如我从山西去青岛,通过石家庄这个点和北京这个点,其中通过石家庄这个点的距离是1000公里,而通过北京这个点是1500公里,这样我就把我到青岛的距离缩到最小1000公里。其中北京和石家庄相当于中间点。了解了这个算法之后呢,我们接下来就得用一个特别的输入方式,具体代码讲解如下。

    int a,b,c;cin>>a>>b>>c;这个是我们的三个初值,结点数,道路数,和对应的付费
	vector<vector<int> >maps(a+10,vector<int>(a+10,0));这个矩阵是保存临接矩阵
    vector<int>vis(a+1,0);判断对应点是不是起始点和结束点
	for(int i=1;i<=a;i++)
	{
		for(int i1=1;i1<=a;i1++)
		{
			maps[i][i1]=(i==i1)?0:1e9;
		}
	}
	for(int i=0;i<b;i++)
	{
		int x,y,z;cin>>x;这个x是起始点
		vis[x]=1;端点处的终点站的值设为1
		while(1)
		{
			cin>>y>>z;
			maps[x][z]=maps[z][x]=min(maps[x][z],y);
			x=z;
			char ch=getchar();
			if(ch=='\n')break;当输入回车的时候结束一行的输入
		}
		vis[x]=1;终点站的值也设为1
	}
	
	for(int i=1;i<=a;i++)  Flody算法
	{
		for(int i1=1;i1<=a;i1++)
		{
			for(int i2=1;i2<=a;i2++)
			{
				maps[i1][i2]=min(maps[i1][i2],maps[i1][i]+maps[i][i2]);
			}
		}
	}

之后我们将每一个价钱的最远距离保存下来,并将这个对应到达的地点,就和第一道题那样,将该地点保存在对应空间内,就跟临接表一样。具体代码详解如下

	map<int,int>hi;这个是方便保存用的就是hi[int(对应钱数)]=最远的距离
    vector<int>go[210];这个是临接表的储存法
    for(int i=1;i<=a;i++)
	{
	 hi.clear();每一次使用要清以下,以防重复使用
	 for(int i1=1;i1<=a;i1++)
	 {
	 	if(i==i1||maps[i][i1]==1e9)continue;边界条件直接跳过
	 	hi[maps[i][i1]/c+2]=max(maps[i][i1],hi[maps[i][i1]/c+2]);保存该价钱的最远距离
	 }
	 for(int i1=1;i1<=a;i1++)
	 {
	 	if(maps[i][i1]==1e9)continue;边界条件直接跳过
	 	if(maps[i][i1]==hi[maps[i][i1]/c+2]||i==i1||vis[i1]==1)go[i].push_back(i1);
        这个是临界表形式的储存方式,
        如果这个价钱的最远距离找到了,可以出站,还有就是两端终点站可以出站,
        还有就是出发站可以出战分别对应以上三个条件
	 }
	}	

之后就是用深度优先遍历的形式判断从对应点出发可以到达哪些点,具体操作如下跟第一题一样。

	vector<int>go[210];
    int bo[210];判断该结点是否遍历过
    void dfs(int p)
    {   bo[p]=1;
	   for(int i=0;i<go[p].size();i++)
	  {
		if(bo[go[p][i]]==0)
		dfs(go[p][i]);
	  }
    }
    int p;cin>>p;
	while(p--)
	{
		memset(bo,0,sizeof(bo));每次都要重置
		int sm;cin>>sm;
		dfs(sm);开始从该结点处遍历。
		vector<int>ji;
		for(int i=1;i<=a;i++)把遍历过的点就是能到达的点都按顺序存起来
		{
			if(bo[i]!=0)ji.push_back(i);
		}
		for(int i=0;i<ji.size();i++)最后输出
        {
            if(i==0)cout<<ji[i];
            else cout<<" "<<ji[i];
        }
		cout<<endl;
	}

以上就是我们的具体步骤

接下来就是我们的最终代码

#include<bits/stdc++.h>
using namespace std;
vector<int>go[210];
int bo[210];
void dfs(int p)
{   bo[p]=1;
	for(int i=0;i<go[p].size();i++)
	{
		if(bo[go[p][i]]==0)
		dfs(go[p][i]);
	}
}
int main()
{
	int a,b,c;cin>>a>>b>>c;
	vector<vector<int> >maps(a+10,vector<int>(a+10,0));
    vector<int>vis(a+1,0);
	for(int i=1;i<=a;i++)
	{
		for(int i1=1;i1<=a;i1++)
		{
			maps[i][i1]=(i==i1)?0:1e9;
		}
	}
	for(int i=0;i<b;i++)
	{
		int x,y,z;cin>>x;
		vis[x]=1;
		while(1)
		{
			cin>>y>>z;
			maps[x][z]=maps[z][x]=min(maps[x][z],y);
			x=z;
			char ch=getchar();
			if(ch=='\n')break;
		}
		vis[x]=1;
	}
	
	for(int i=1;i<=a;i++)
	{
		for(int i1=1;i1<=a;i1++)
		{
			for(int i2=1;i2<=a;i2++)
			{
				maps[i1][i2]=min(maps[i1][i2],maps[i1][i]+maps[i][i2]);
			}
		}
	}
	map<int,int>hi;
    for(int i=1;i<=a;i++)
	{
	 hi.clear();
	 for(int i1=1;i1<=a;i1++)
	 {
	 	if(i==i1||maps[i][i1]==1e9)continue;
	 	hi[maps[i][i1]/c+2]=max(maps[i][i1],hi[maps[i][i1]/c+2]);
	 }
	 for(int i1=1;i1<=a;i1++)
	 {
	 	if(maps[i][i1]==1e9)continue;
	 	if(maps[i][i1]==hi[maps[i][i1]/c+2]||i==i1||vis[i1]==1)go[i].push_back(i1);
	 }
	}	
	int p;cin>>p;
	while(p--)
	{
		memset(bo,0,sizeof(bo));
		int sm;cin>>sm;
		dfs(sm);
		vector<int>ji;
		for(int i=1;i<=a;i++)
		{
			if(bo[i]!=0)ji.push_back(i);
		}
		for(int i=0;i<ji.size();i++)
        {
            if(i==0)cout<<ji[i];
            else cout<<" "<<ji[i];
        }
		cout<<endl;
	}
	
	
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

B程洪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值