最短路问题详解+题目
概念
若网络中的每条边都有一个数值(长度、成本、时间等),则找出两节点(通常是源节点和阱节点)之间总权和最小的路径就是最短路问题
-
算法
- Floyd-warshall算法
(1)介绍:非常的好用,通常可以在任何图中使用,包括有向图、带负权边的图。
(2)算法讲解:Floyd算法 从第一个顶点开始,依次将每个顶点作为媒介k,然后对于每一对顶点u和v,查看其是否存在一条经过k的,
距离比已知路径更短的路径,
如果存在则更新它。
- Dijkstra算法
(1)介绍:是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,
直到扩展到终点为止。注意该算法要求图中不存在负权边。
(2)算法讲解:用贪心实现,先把起点到所有点的距离存下来找个最短的,进行松弛操作再找出最短的,把所有的点找遍之后就存下了
起点到其他所有点的最短距离。
> 松弛操作:遍历一遍看通过刚刚找到的距离最短的点作为中转站会不会更近,如果更近了就更新距离
> 注意:除了距离起点的距离为0外,其他距离均设为无穷大。
- 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;
}