最短路问题详解+题目

概念

  若网络中的每条边都有一个数值(长度、成本、时间等),则找出两节点(通常是源节点和阱节点)之间总权和最小的路径就是最短路问题
  • 算法

  1. Floyd-warshall算法
  (1)介绍:非常的好用,通常可以在任何图中使用,包括有向图、带负权边的图。  
  (2)算法讲解:Floyd算法 从第一个顶点开始,依次将每个顶点作为媒介k,然后对于每一对顶点u和v,查看其是否存在一条经过k的,
距离比已知路径更短的路径,
如果存在则更新它。
  1. Dijkstra算法
   (1)介绍:是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,
直到扩展到终点为止。注意该算法要求图中不存在负权边。
   (2)算法讲解:用贪心实现,先把起点到所有点的距离存下来找个最短的,进行松弛操作再找出最短的,把所有的点找遍之后就存下了
起点到其他所有点的最短距离。   
 
> 松弛操作:遍历一遍看通过刚刚找到的距离最短的点作为中转站会不会更近,如果更近了就更新距离
> 注意:除了距离起点的距离为0外,其他距离均设为无穷大。
  1. Bellman-Ford算法
   (1)介绍:Bellman-ford算法 适用于单源最短路径,图中边的权重可为负数即负权边,但不可以出现负权环。  

> 负权边:为负数的边。
> 负权环:源点到源点的一个环,环上权重和为负数。

   (2)算法讲解:
      1.初始化:除了起点的距离为0外,其他均设为无穷大。
      2.迭代求解:循环对边集合E的每条边进行松弛操作,使得顶点集合V中的每个顶点v的距离长逐步逼近最终等于其最短距离长;
      3.验证是否负权环:再对每条边进行松弛操作。如果还能有一条边能进行松弛,那么就返回False,否则算法返回True
  • 题目

输入:

第一行n表示边的个数,接下来n行a,b,len,最后一行s,t

求点s到点t的距离

输入样例
7
1 2 2
2 5 2
1 3 4
2 3 1
3 5 6
1 4 7
3 4 1

Dijkstra打法

#include <bits/stdc++.h>
#define maxx 0x7f
using namespace std;
int u[105][105]={0x7f},dis[105];
bool vis[105]={false};
int main(){
	int n,s,t,x,y,minn,k;
	cin>>n;
	for (int i=1;i<=n;i++)
	{
		dis[i]=maxx;
		vis[i]=false;
	}
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			u[i][j]=maxx;
	for (int i=1;i<=n;i++)
	{
		cin>>x>>y;
		cin>>u[x][y];
	}
	cin>>s>>t;
	for (int i=1;i<=n;i++)
		dis[i]=u[s][i];
	dis[s]=0;
	vis[s]=true;
	for (int i=1;i<=n;i++)
	{
		minn=maxx;
		k=0;
		for (int j=1;j<=n;j++)
			if (vis[j]==false&&dis[j]<minn)
			{
				minn=dis[j];
				k=j;
			}
		if (k==0)	break;
		vis[k]=true;
		for (int j=1;j<=n;j++)
			if (dis[k]+u[k][j]<dis[j])
				dis[j]=dis[k]+u[k][j];
	}
	cout<<dis[t];
	return 0;
}

floyd打法

#include <bits/stdc++.h>            
using namespace std;                
const int maxx=0x7f;                
int u[105][105];                    
int main(){                         
	int s,t,n,x,y;                     
	cin>>n;
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			u[i][j]=0x7f;                            
	for (int i=1;i<=n;i++)             
	{                                  
		cin>>x>>y;                        
		cin>>u[x][y];                     
	}                                  
	cin>>s>>t;                         
	for (int k=1;k<=n;k++)             
		for (int i=1;i<=n;i++)            
			for (int j=1;j<=n;j++)         
			{                                
				if (i!=j&&i!=k&&j!=k&&u[i][j]>u[i][k]+u[k][j])
					u[i][j]=u[i][k]+u[k][j];
			}
	cout<<u[s][t];
	return 0;
}

P1364 医院设置

题目大意

找一个点使得到其他点的距离总和最小

Floyed穷举出答案

#include <bits/stdc++.h>
using namespace std;
const int inf=100000007;
int p[105],dis[105][105],sum;
int n,lch,rch;
int main()
{
    cin>>n;
    memset(dis,inf,sizeof(dis));
    for(int i=1;i<=n;i++)
    {
        dis[i][i]=0;
        cin>>p[i];
        cin>>lch>>rch;
        if(lch>=0) dis[i][lch]=1;dis[lch][i]=1;
        if(rch>=0) dis[i][rch]=1;dis[rch][i]=1;
    }
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(dis[i][j]>dis[i][k]+dis[k][j]) dis[i][j]=dis[i][k]+dis[k][j];
    int minn=inf;
    for(int i=1;i<=n;i++)
    {
        sum=0;
        for(int j=1;j<=n;j++)
            sum+=p[j]*dis[i][j];
        if(minn>sum) minn=sum;
    }
    cout<<minn<<endl;
    return 0;
}
posted @ 2021-08-15 18:24  hewt  阅读(250)  评论(0编辑  收藏  举报