每日总结之最短路径 4.2 +Floyed+dijkstra

本文介绍了Floyed和Dijkstra两种算法在求解图中两点间最短路径的应用。Floyed算法通过三重循环实时更新所有节点间的最短路径,而Dijkstra算法则是单源最短路径算法,从起点开始逐步扩展找到到其他点的最短路径。此外,还提供了两个基于这些算法的实际编程题目:租用游艇问题和修路问题,分别展示了如何在实际场景中运用这两种算法。
摘要由CSDN通过智能技术生成

目录

算法

 Floyed   O(n*3)

dijkstra--单源最短路径算法 O(n*2)

 刷题

1.租用游艇

 2.修路

算法

 多源Floyed   O(n*3)


原理:

利用三重循环,实时更新最短路径;

1.含义:

a【i】【j】:i--j 直接距离

a【i】【k】+ a【k】【j】:i--j 间接距离(经过k中转站)

2.解释:

求 i--j 的最短路径则讨论 i--j,i--1站点--j,i-2站点--j,i--3站点--j... ...

依次枚举比大小,实时更新

	for(k=1; k<=n; k++)        //依次枚举 1-n中转站,比大小 
		for(i=1; i<=n; i++)
			for(j=1; j<=n; j++)
			{
				if(a[i][j]>a[i][k]+a[k][j])
					a[i][j]=a[i][k]+a[k][j];
			}

  

推导: 

 

dijkstra--单源最短路径算法 O(n*2)


原理:

唯一起点到其他点的最短路径的算法,即单源最短路径算法

1.何为单源:

从同一起点出发到其他点,求1->2,1->3,1->4最短路径

2.含义:

dis【v】:表示某一固定点到第v点的最短路径的值

dis【u】:  表示前结点(已确定最短路径)的值

w【u】【v】:表示 u->v的距离

3.初始化:

起点s:dis【s】=0,其他点:dis【v】=∞;

4.核心:从最短距离开始找(找最小边kruskal算法)+更新dis【】数组

①从最小距离开始,再次小距离... ...

 for(int i=1;i<=n;i++)
       {    if(!book[i]&&minn>dis[i])
            {  minn=dis[i];         //从未标记中找最小距离及其下标
                t=i;      }
      }      

②最初的dis【v】:为1--v的直接距离;

    更新的dis【v】:为1--v的间接距离;

if (dis【u】+ w【u】【v】< dis【v】)

{   dis【v】=dis【u】+ w【u】【v】;   }

即最终dis【v】为最短路径;

//a【i】【j】:存储已知i->j的距离
//dis【t】:定点s到t的最短距离

void dijk(int s)
{
    memset(book,0,sizeof(book));
    memset(dis,999999,sizeof(dis));
    dis[s]=0;
    while(1)
    {
        int t=0,minn=999999;
        for(int i=1;i<=n;i++)
        {
            if(!book[i]&&minn>dis[i])
            {
                minn=dis[i];         //从未标记中找最小距离及其下标
                t=i;
            }
        }
        
        book[t]=1;                  //标记t点,进入以下循环
        if(t==0) break;            //点全被标记,跳出循环
        
        for(int i=1;i<=n;i++)      //更新dis【】最短路径数组
        {
            if(dis[i]>dis[t]+a[t][i])     //dis【】为s点直接到i点的距离
                dis[i]=dis[t]+a[t][i];    //dis[t]+a[t][i]为s点经过t点到达i点的间接距离
        }
        
    }
}

 刷题

1.租用游艇

P1359 租用游艇 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1359

1.格式化输入二维数组:1-2,1-3,1-4,2-3,2-4,3-4... ...

                                       for(int i=1; i<=n-1; i++)
                                             for(int
j=i+1; j<=n; j++)

2.三重for循环枚举路径:第一层for枚举1-k中转站,第二,三层为 i站点--j站点直达所需距离

3.输出1-n(a[1][n])的最短路径:有序!1-n ≠ n-1

#include<stdio.h>
#include<string.h>
int main()
{
	int n,a[210][210];
	scanf("%d",&n);
	memset(a,1,sizeof(a));                //数组初值赋大数
	for(int i=1; i<=n-1; i++)                  //注意输入格式 
	{
		for(int j=i+1; j<=n; j++) 
		{
			scanf("%d",&a[i][j]);
		}
	}
	for(int k=1; k<=n; k++)               //枚举1-k中转站
	{
		for(int i=1; i<=n; i++)
		{
			for(int j=1; j<=n; j++)
			{
				if(a[i][j]>a[i][k]+a[k][j])
				{
					a[i][j]=a[i][k]+a[k][j];
				}
			}
		}
	}
	printf("%d",a[1][n]);               //1-n的最短路径
}

 2.修路

P2872 [USACO07DEC]Building Roads S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P2872

1.变量设置:结构体存储:点1+点2+1到2的距离

2.初始化&&找find father:并查集基本操作

3.升序排序距离:调用库函数,快排不行

4.unionn时加入权值(距离):

5.终止条件:sum==n-1,线全部用完

6.注意:条件已知已连接点点,两点距离设为0即可

#include<bits/stdc++.h>
using namespace std;
int fa[500501];
long double ans=0.0;
int sum=0;
int k=0;

struct node
{
	int x,y;
	double z;
} a[500501];

void init(int n)
{
	for(int i=1; i<=n; i++)
	{
		fa[i]=i;
	}
}

int find(int i)
{
	if(fa[i]==i) return i;
	else
	{
		return find(fa[i]);
	}
}

/*void quick(int left,int right)
{
	int i=left,j=right;
	struct node t,temp;
	temp=a[left];

	while(i!=j)
	{
		while(i<j&&a[j].z>=temp.z)
		{
			j--;
		}
		while(i<j&&a[i].z<=temp.z)
		{
			i++;
		}
		if(i<j)
		{
			t=a[i];
			a[i]=a[j];
			a[j]=t;
		}
	}
	a[left]=a[i];
	a[i]=temp;

	quick(left,i-1);
	quick(j+1,right);

}
*/

bool cmp(node a,node b)
{
    return a.z<b.z;
}


void add(int i,int j,double l)        //构造结构体存储两点间距离(点+点+距离) 
{
	a[++k].x=i;
	a[k].y=j;
	a[k].z=l;
}

int main()
{
	int i,j,m,n,b,c;
	int xx[500501],yy[500501];
	scanf("%d %d",&n,&m);
	init(n);
	
	for(i=1; i<=n; i++)
	{
		scanf("%d %d",&xx[i],&yy[i]);
	}

	for(i=1; i<=n; i++)
		for(j=i+1; j<=n; j++)
		{
			long double z=(double)sqrt((double)(xx[i]-xx[j])*(xx[i]-xx[j])+(double)(yy[i]-yy[j])*(yy[i]-yy[j]));
			add(i,j,z);
		}

	for(i=1; i<=m; i++)
	{
		scanf("%d %d",&b,&c);
		add(b,c,0.0);
	}

	//quick(1,k);
	  sort(a+1,a+1+k,cmp); 

	for(i=1; i<=k; i++)
	{
		int x=find(a[i].x);
		int y=find(a[i].y);
		if(x!=y)
		{
			fa[x]=y;
			sum++;                    //线使用量+1 
			ans+=a[i].z;             //权值求和 
		}
		
		if(sum==n-1) break;         //n为点个数,n-1为线个数 
	}
 printf("%.2Lf",ans);
    return 0; 
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值