乍一看搜索跟这个一样都可以找出一个点到另一个点的最短距离,但是有些问题两者都可以解决,而另一些搜索就不能解决了,搜索有确定的方向一步一步走,而最短路是告诉你某两个点直接可以直接走,没有确定的方向。最短路问题,通俗的说就是就是给你n个点,m条边,然后找出某两个点之间的最短距离。解决最短路常用的有三种算法Floyd、Dijkstra、SPFA。三种方法各有优劣
在一个无权的图中,若从一个顶点到另一个顶点存在着一条路径,则称该路径长度为该路径上所经过的边的数目,它等于该路径上的顶点数减1。由于从一个顶点到另一个顶点可能存在着多条路径,每条路径上所经过的边数可能不同,即路径长度不同,把路径长度最短(即经过的边数最少)的那条路径叫作最短路径或者最短距离。
对于带权的图,考虑路径上各边的权值,则通常把一条路径上所经边的权值之和定义为该路径的路径长度或带权路径长度。从源点到终点可能不止一条路径,把带权路径长度最短的那条路径称为最短路径,其路径长度(权值之和)称为最短路径长度或最短距离。
Floyd算法比较简单,就是暴力枚举了所有的可能,将所有可能找遍就知道了两点之间的最短路
Chara数组 :储存两点间的距离,Chara[i][j]的值就是点i到点j的距离。
n:总共有n个点。
p[i][j]:代表对应顶点的最小路径的前驱矩阵
MAX:定义最大值,路不通的情况距离就是MAX
很容易理解,我们从一个点i到另一个点j,无非就两种走法
if(Chara[i][j] > Chara[i][k] + Chara[k][j])
Chara[i][j] = Chara[i][k] + Chara[k][j];
#define MAX 65535
int Chara[N][N],p[N][N];
int n,m;
void Floyd()
{
for(int i=0;i<n;i++)
{
for(int j=0;j
{
p[i][j]=j;//初始化
}
}
for(int k=0;k
{
for(int i=0;i
{
for(int j=0;j
{
if(Chara[i][k] == MAX || Chara[k][j] == MAX) continue;
if(Chara[i][j] > Chara[i][k] + Chara[k][j])
{
//如果经过下标k顶点路径比原两点间路径更短
//将当前两点权值设为更小的那一个
Chara[i][j] = Chara[i][k] + Chara[k][j];
p[i][j]=p[i][k];//路径设置经过下标k的顶点
}
}
}
}
Dijkstra算法算是贪心思想实现的,首先把起点到所有点的距离存下来找个最短的,然后松弛一次再找出最短的,所谓的松弛操作就是,遍历一遍看通过刚刚找到的距离最短的点作为中转站会不会更近,如果更近了就更新距离,这样把所有的点找遍之后就存下了起点到其他所有点的最短距离,下面仔细讲。
Chara数组 :储存两点间的距离,Chara[i][j]的值就是点i到点j的距离。
dis数组:储存起点到各个点的距离,dis[i]就是起点到i点的距离。
vis数组:标记点是否访问过
INF:宏定义的最大值路不通
#define INF 65535
int n,m,s,t;
int Chara[N][N],dis[N],vis[N],p[i];
void Dijkstra(int src) //src传入的起点
{
for(int i=0; i//初始化起点到所有点的距离
{
dis[i] = Chara[src][i];
vis[i] = 0;
p[i]=0;
}
dis[src] = 0; //到自身距离为0
vis[src] = 1; //标记 注src=0
for(int i=0; iint ans = INF,k;
for(int j=0; j// 寻找未被访问过距离起点v0最近的
{
if(!vis[j] && dis[j] < ans)
{
k = j;
ans = dis[j];
}
}
vis[k] = 1; //标记已访问
if(ans == INF) break; //表示剩下所有点都不通
for(int j =0; j//松弛操作,更新起点到所有未访问点的距离
{
if(!vis[j] && dis[k] + Chara[k][j]//存放前驱节点
}
}
}
}
SPFA是一种用队列优化的B-F算法,看上去和BFS很像,B-F效率较低就不介绍了,还有一种用DFS优化B-F的SPFA但是往往这种方法比平时更加劣化没有队列优化的好用,平时用SPFA就够用了。可以解决负边问题,可以判断负环是否存在。在稀疏图中,采用类似邻接链表储存比较节省空间。
node结构体:用来储存边,数组下标代表边起点,结构体中的v,代表边的终点,weight/w代表权值
dis数组:储存起点到各个点的距离,dis[i]就是起点到i点的距离。
vis数组:标记点是否访问过
INF:宏定义的最大值路不通
const int INF=0x3f3f3f3f;
const int N=210;
int n,m,s,t;
int dis[N],vis[N],sum[N];
struct node{
int v; ///点
int weight; ///权值
};
vector mp[N]; //储存边;
//SPFA写法
void SPFA(int src)
{
int q;
queue<int>Q;
vis[src] = 1;
dis[src] = 0;
Q.push(src);
while(!Q.empty())
{
q = Q.front();
Q.pop();
vis[q] = 0;
for(int i=0;iif(dis[q] + mp[q][i].weight < dis[mp[q][i].v])
{
dis[mp[q][i].v] = dis[q] + mp[q][i].weight;
if(!vis[mp[q][i].v])
{
Q.push(mp[q][i].v);
vis[mp[q][i].v] = 1;
}
}
}
}
return ;
}
HDU1847-畅通工程续
#include
using namespace std;
const int INF=0x3f3f3f3f;
const int N=300;
int n,m,s,t,i,j,k;
int Chara[N][N];
void Floyd()
{
for(i=0;ifor(j=0;jfor(k=0;kif(Chara[j][i]+Chara[i][k]int main()
{
while(~scanf("%d %d",&n,&m))
{
int a,b,x;
memset(Chara,0x3f,sizeof(Chara));
for(int i=0;i<=n;i++)
Chara[i][i] = 0;
for(int i=0;iscanf("%d %d %d",&a,&b,&x);
if(x< Chara[a][b])
Chara[a][b]=Chara[b][a]=x;
}
scanf("%d %d",&s,&t);
Floyd();
if(Chara[s][t]==INF)
cout<<-1<else
cout<return 0;
}
#include
using namespace std;
const int INF=0x3f3f3f3f;
const int N=210;
int n,m,s,t;
int Chara[N][N],dis[N],vis[N],sum[N];
void Dijkstra(int src)
{
for(int i=0; i0;
}
dis[src] = 0;
vis[src] = 1;
for(int i=0; iint ans = INF,k;
for(int j=0; jif(!vis[j] && dis[j] < ans)
{
k = j;
ans = dis[j];
}
}
vis[k] = 1;
if(ans == INF) break;
for(int j =0; jif(!vis[j] && dis[j] > dis[k] + Chara[k][j])
{
dis[j] = dis[k] + Chara[k][j];
}
}
}
}
int main()
{
while(~scanf("%d %d",&m,&n))
{
int u,v,w;
memset(Chara,0x3f,sizeof(Chara));
for(int i=0; iscanf("%d %d %d",&u,&v,&w);
if(w < Chara[u][v])
Chara[u][v] = Chara[v][u] = w;
}
scanf("%d %d",&s,&t);
Dijkstra(s);
printf("%d\n",dis[t]==INF?-1:dis[t]);
}
return 0;
}
#include
using namespace std;
const int INF=0x3f3f3f3f;
const int N=210;
int n,m,s,t;
int Chara[N][N],dis[N],vis[N],sum[N];
struct node{
int v; ///点
int weight; ///权值
};
vector mp[N]; //储存边;
//SPFA写法
void SPFA(int src)
{
int q;
queue<int>Q;
vis[src] = 1;
dis[src] = 0;
Q.push(src);
while(!Q.empty())
{
q = Q.front();
Q.pop();
vis[q] = 0;
for(int i=0;iif(dis[q] + mp[q][i].weight < dis[mp[q][i].v])
{
dis[mp[q][i].v] = dis[q] + mp[q][i].weight;
if(!vis[mp[q][i].v])
{
Q.push(mp[q][i].v);
vis[mp[q][i].v] = 1;
}
}
}
}
return ;
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
memset(dis,INF,sizeof(dis));
memset(vis,0,sizeof(vis));
int u,v,w;
node ans;
for(int i=0;iscanf("%d %d %d",&u,&v,&w);
ans.v = v;
ans.weight = w;
mp[u].push_back(ans);
ans.v = u;
mp[v].push_back(ans);
}
scanf("%d %d",&s,&t);
SPFA(s);
printf("%d\n",dis[t]==INF?-1:dis[t]);
for(int i=0;ireturn 0;
}