Dijkstra与Floyd算法解最短路问题(注意路径的保存,十分巧妙):
个人理解两个算法都有点动态规划的意思,都是用局部最优解展开求。
最好的关于Dijkstra的讲解与流程图还得是殷剑宏离散数学里面的。在这里做个笔记以免忘记。
书中题目题目的解法:
Dijkstra解法:
结合上面题目并耐心走流程图表就可以理解。
/*离散数学P218*/
#include<iostream>
using namespace std;
const int maxnode=6;//最大点数
const int maxline=9;//最大变数
int dist[maxnode];
bool visit[maxnode];
int G[maxnode][maxnode];
int INF=0x7ffff;//无穷
int path[maxnode];//保存路径
void Dijstra(int v0)
{
for(int i=0;i<maxnode;i++){
dist[i]=G[v0][i];//记录源点到所有点的距离
visit[i]=false;//所有点都标记为未访问
path[i]=v0;//初始化指定所有节点的前驱结点都是自己
}
dist[v0]=0;//标志当前距离为0
visit[v0]=true; //设置源点为已访问
int temp_maxnode=maxnode;
while(temp_maxnode--){//不断循环让查找深入(因为有visit[]是全局变量,所以可以继续)
int u;
int mindist=INF;
for(int i=0;i<maxnode;i++){//循环找出所有到源点的最短路的点
if(!visit[i]&&dist[i]<mindist){//如果没有被访问并且这个点比保存的最小值还要小
mindist=dist[i];
u=i;
}
}
visit[u]=true;//找到的最小的并标记为访问过。
for(int i=0;i<maxnode;i++)
if(!visit[i]&&dist[u]+G[u][i]<dist[i]){//如果源点到目的点的最小值+这个点到下一个点的距离<源点直接到下一个点的距离
dist[i]=dist[u]+G[u][i];//更新源点到这个点的最小距离
path[i]=u;
}
}
}
void printPath(int src,int end)
{
while(src!=end){
cout<<path[end]<<"->";
end=path[end];
}
}
int main()
{
for(int i=0;i<maxnode;i++)
for(int j=0;j<maxnode;j++)
{
G[i][j]=INF;
if(i==j) G[i][j]=0;//自己到自己初始化为0
}
//
G[0][1]=4; G[0][2]=2;
G[1][2]=1; G[1][3]=5;
G[2][4]=10; G[2][3]=8;
G[3][4]=2; G[3][5]=6;
G[4][5]=3;
G[1][0]=4; G[2][0]=2;
G[2][1]=1; G[3][1]=5;
G[4][2]=10; G[3][2]=8;
G[4][3]=2; G[5][3]=6;
G[5][4]=3;
int node_src;
scanf("%d",&node_src);
Dijstra(node_src);
for(int i=0;i<maxnode;i++)
printf("%d ",dist[i]);
cout<<endl;
for(int i=0;i<maxnode;i++){
printPath(node_src,i);
cout<<endl;
}
return 0;
}
Floyd算法解此题:
如果只经过一个点1,判断是否能够收缩:
{
for(j=1;j<=n;j++)
{
if ( e[i][j] > e[i][1]+e[1][j] )
e[i][j] = e[i][1]+e[1][j];
}
}
多个点(注意防止溢出):
for(int k=0;k<max_node;k++)
for(int i=0;i<max_node;i++)
for(int j=0;j<max_node;j++)
if(!(G[i][k]==INF||G[k][j]==INF)&&G[i][k]+G[k][j]<G[i][j]){//加判断防止溢出
G[i][j]=G[k][j]+G[i][k];
}
code:
#include<iostream>
#include<vector>
using namespace std;
const int max_node=6;
int G[max_node][max_node];
int INF=0x7ffff;
int path[max_node][max_node];
void floyd()
{
for(int i=0;i<max_node;i++)
for(int j=0;j<max_node;j++)
if(G[i][j]==INF) path[i][j]=-1;
else path[i][j]=i;//记录前驱
for(int k=0;k<max_node;k++)//更新两点间的最短路
for(int i=0;i<max_node;i++)
for(int j=0;j<max_node;j++)
if(!(G[i][k]==INF||G[k][j]==INF)&&G[i][k]+G[k][j]<G[i][j]){//加判断防止溢出
G[i][j]=G[k][j]+G[i][k];
path[i][j]=path[k][j];//只记录前驱最后查找
}
}
void printPath(int to,int from)//floyd输出路径
{
cout<<to;
while(from!=to){
cout<<"->"<<path[from][to];
to=path[from][to];
}
}
int main()
{
for(int i=0;i<max_node;i++)
for(int j=0;j<max_node;j++){
G[i][j]=INF;
if(i==j) G[i][j]=0;//自己到自己初始化为0
}
G[0][1]=4;G[0][2]=2;
G[1][2]=1; G[1][3]=5;
G[2][4]=10; G[2][3]=8;
G[3][4]=2;G[3][5]=6;
G[4][5]=3;
G[1][0]=4;G[2][0]=2;
G[2][1]=1; G[3][1]=5;
G[4][2]=10; G[3][2]=8;
G[4][3]=2;G[5][3]=6;
G[5][4]=3;
floyd();
cout<<endl;
printPath(3,0);
return 0;
}