1.单源的,从有向图某个源点, 到其他点的最短路径
利用算法迪杰斯特拉算法;
Dijkstra算法的基本思想:
一个辅助数组D[max_v];每个D[i]表示当前所知源点到vi的最短路径的长度
一个辅助集合S,记录已找到最短路径的顶点的集合,他是逐步补充的;知道S集合包括所有点,起初S集合包含源点
1.先找出源点直接可达到顶点i,并把权记录到D[i]中,不可达到顶点记为最大值;
2.然后进行n-1次循环,把其他点一次找出最短路径;
每次循环先找出D中最小的值min,和v(D[v]=min); 把v加入到集合S中,
3.然后寻找不属于S集合的点w,如果min+dut(v-w的权值)<D[w],则更新D[w]的值,
4.重复2,和3,知道S集合包括所有点。
下面是代码,我自己又写了一个函数来呈现结果,
#include<iostream>
#include<fstream>
#define Max_v 200
using namespace std;
//算法7.15 最短路径
struct Arccell{
int adj;
};
typedef Arccell adjmatric[Max_v][Max_v];
struct Mgraph{
char vexs[Max_v]; //顶点向量
adjmatric arcs; //邻接矩阵
int vexnum,arcnum; //顶点数 和 弧数
};
int locate(Mgraph G,char ch){
for(int i=0;i!=G.vexnum;++i){
if(G.vexs[i]==ch)return i;
}
}
void createDG(Mgraph &G){//采用数组表示法,构造有向图
cout<<"Please enter the vexnum and arcnum of the G graph"<<endl;
cin>>G.vexnum>>G.arcnum;
cout<<"Please enter the dians of G"<<endl;
for(int i=0;i!=G.vexnum;++i){cin>>G.vexs[i];}//构造顶点向量
for(int i=0;i!=G.vexnum;++i){//初始化矩阵
for(int j=0;j!=G.vexnum;++j){
G.arcs[i][j].adj=10000;
}
}
char v1,v2;int w;
cout<<"Please enter "<<G.arcnum<<" arcnums"<<endl;
for(int k=0;k!=G.arcnum;++k){
cin>>v1>>v2>>w;
int i=locate(G,v1); int j=locate(G,v2);
G.arcs[i][j].adj=w;
}
}
void printgraph(Mgraph M){
cout<<"\n"<<"The graph has "<<M.vexnum<<"vertex and "<<M.arcnum<<"arc"<<endl;
cout<<"The vertex is:"; for(int i=0;i!=M.vexnum;++i){cout<<M.vexs[i]<<" ";}
cout<<endl;
for(int i=0;i!=M.vexnum;++i){
for(int j=0;j!=M.vexnum;++j){
if(M.arcs[i][j].adj!=10000)
cout<<M.vexs[i]<<" "<<M.vexs[j]<<endl;
}
}
for(int i=0;i!=M.vexnum;++i){
for(int j=0;j!=M.vexnum;++j){
cout<<M.arcs[i][j].adj<<" ";
}cout<<endl;
}
}
//单源,某顶点到各顶点的最短路径
void Shortestpath(Mgraph G,int v0,int ppp[][Max_v],int*D)
{
for(int i=0;i!=Max_v;++i){ //初始化pathbool
for(int j=0;j!=Max_v;++j){
ppp[i][j]=false;
}
}
bool finals[Max_v];//如果finals[v]为true,则已经求得v0到v的最短路径了
for(int v=0;v!=G.vexnum;++v){
finals[v]=false; D[v]=G.arcs[v0][v].adj; //初始化
for(int w=0;w!=G.vexnum;++w){ ppp[v][w]=false;}//设置空路径
if(D[v]<10000){ppp[v][v0]=true; ppp[v][v]=true;}//目前找到的最短的路径
}
D[v0]=0;finals[v0]=true;//v0属于s集
int v;
//开始主循环,每次求得v0到某个v顶点的最短路径,并加到s集中
for(int i=1;i!=G.vexnum;++i){//其余G.vexnum-1个顶点
int mins=10000;
for(int w=0;w!=G.vexnum;++w){//当前已知离v0最近的点,并把其加到s集中。随后更新已知到顶点的最短长度
if(!finals[w]&&D[w]<mins){ v=w;mins=D[w];}
}
finals[v]=true;
for(int w=0;w!=G.vexnum;++w){
if(!finals[w]&&(mins+G.arcs[v][w].adj<D[w])){//w不在s集,更新最短距离
D[w]=mins+G.arcs[v][w].adj;
for(int i=0;i!=Max_v;++i){
ppp[w][i]=ppp[v][i];
}
ppp[w][w]=true;
}
}
}//for
}
bool yes(Mgraph G,int tem,int j){
if(G.arcs[tem][j].adj!=10000)return true;
else return false;
}
//打印结果
void printresult(Mgraph G,int v0,int ppp[][Max_v],int*D)
{
for(int i=0;i!=G.vexnum;++i){
if(i!=v0){
if(D[i]==10000)cout<<" "<<G.vexs[v0]<<"-->>"<<G.vexs[i]<<" 无路径,不可达"<<endl;//路径长度等于最大值,则不可达
else{
cout<<" "<<G.vexs[v0]<<"-->>"<<G.vexs[i]<<" 长度:"<<"="<<" "<<D[i]<<" 路径:"<<G.vexs[v0]<<" ";
int tem=v0;
for(int j=0;j!=G.vexnum;++j){//根据数组pathbool来找到路径
if(ppp[i][j]==1&&j!=v0&&j!=i&&yes(G,tem,j)){
cout<<G.vexs[j]<<" " ;
ppp[i][j]=0;
tem=j;
j=0;
}
}
cout<<G.vexs[i]<<endl;
}
}
}
}
int main()
{
ifstream infile("rebuf.txt");
streambuf* backup=cin.rdbuf();//记录原状态
cin.rdbuf(infile.rdbuf());
Mgraph m;
createDG(m);
printgraph(m);
cout<<endl;
int pathbool[Max_v][Max_v];//记录路径,如果pathbool[v][w]为true。则w是v0到v最短路径上的顶点
int D[Max_v];//记录当前所找到的从始点到每个终点vi的最短路径的长度
Shortestpath(m,0,pathbool,D);//迪杰斯特拉算法,算法7.15
cout<<endl;
printresult(m,0,pathbool,D);//打印结果
cout<<endl;
cin.rdbuf(backup);//解绑重定向
//利用迪杰斯特拉算法来求一对顶点之间的最短路径
cout<<"请输入起点";
char x,y;
cin>>x;
Shortestpath(m,locate(m,x),pathbool,D);
cout<<"请输入终点";
cin>>y;
int iy=locate(m,y);
if(D[iy]==10000)cout<<"不可达"<<endl;
else{
cout<<" "<<m.vexs[locate(m,x)]<<"-->>"<<m.vexs[iy]<<" 长度:"<<"="<<" "<<D[iy]<<" 路径:"<<m.vexs[locate(m,x)]<<" ";
int tem=locate(m,x);
int i=iy;
for(int j=0;j!=m.vexnum;++j){//根据数组pathbool来找到路径
if(pathbool[i][j]==1&&j!=locate(m,x)&&j!=i&&yes(m,tem,j)){//类似上面打印结果,这次只需打印一个路径
cout<<m.vexs[j]<<" " ;
pathbool[i][j]=0;
tem=j;
j=0;
}
}cout<<m.vexs[i]<<endl;
}
return 0;
}
rebuf.txt:
6 8
a b c d e f
a c 10
a e 30
a f 100
b c 5
c d 50
d f 10
e d 20
e f 60
运行结果:
2.每一对顶点之间的最短路径
首先可以利用迪杰斯特拉算法来解决,上面最后已经给出了方法。
下面使用弗洛伊德算法,时间复杂度相同,但是形式上更加简洁。
过了一个春节,有好几天没动,真是罪过,今天总算把艰苦的第七章给结束了,Floyd算法。
直接上代码:
#include<iostream>
#include<fstream>
#define Max_v 200
using namespace std;
//算法7.16 最短路径,Floyd算法
struct Arccell{
int adj;
};
typedef Arccell adjmatric[Max_v][Max_v];
struct Mgraph{
char vexs[Max_v]; //顶点向量
adjmatric arcs; //邻接矩阵
int vexnum,arcnum; //顶点数 和 弧数
};
int locate(Mgraph G,char ch){
for(int i=0;i!=G.vexnum;++i){
if(G.vexs[i]==ch)return i;
}
}
void createDG(Mgraph &G){//采用数组表示法,构造有向图
cout<<"Please enter the vexnum and arcnum of the G graph"<<endl;
cin>>G.vexnum>>G.arcnum;
cout<<"Please enter the dians of G"<<endl;
for(int i=0;i!=G.vexnum;++i){cin>>G.vexs[i];}//构造顶点向量
for(int i=0;i!=G.vexnum;++i){//初始化矩阵
for(int j=0;j!=G.vexnum;++j){
if(i==j)G.arcs[i][j].adj=0;
else G.arcs[i][j].adj=10000;
}
}
char v1,v2;int w;
cout<<"Please enter "<<G.arcnum<<" arcnums"<<endl;
for(int k=0;k!=G.arcnum;++k){
cin>>v1>>v2>>w;
int i=locate(G,v1); int j=locate(G,v2);
G.arcs[i][j].adj=w;
}
}
void printgraph(Mgraph M){
cout<<"\n"<<"The graph has "<<M.vexnum<<"vertex and "<<M.arcnum<<"arc"<<endl;
cout<<"The vertex is:"; for(int i=0;i!=M.vexnum;++i){cout<<M.vexs[i]<<" ";}
cout<<endl;
for(int i=0;i!=M.vexnum;++i){
for(int j=0;j!=M.vexnum;++j){
if(M.arcs[i][j].adj!=10000)
cout<<M.vexs[i]<<" "<<M.vexs[j]<<endl;
}
}
for(int i=0;i!=M.vexnum;++i){
for(int j=0;j!=M.vexnum;++j){
cout<<M.arcs[i][j].adj<<" ";
}cout<<endl;
}
}
bool yes(Mgraph G,int tem,int j){
if(G.arcs[tem][j].adj!=10000)return true;
else return false;
}
//算法7.16
void Short_path_floyd(Mgraph G,int p[3][3][3],int D[3][3]){
//若p[v][w][u]为true,则U为v到w当前求得最短路径上的顶点
for(int v=0;v!=G.vexnum;++v){
for(int w=0;w!=G.vexnum;++w)
{
D[v][w]=G.arcs[v][w].adj;
for(int u=0;u!=G.vexnum;++u){p[v][w][u]=false;}
if(D[v][w]<10000){//从v到w有直接路径,设置p
p[v][w][v]=true;
p[v][w][w]=true;
}
}}
for(int u=0;u!=G.vexnum;++u){//最主要过程,不断的用u作为中间点,寻找最短路径
for(int v=0;v!=G.vexnum;++v){
for(int w=0;w!=G.vexnum;++w){
if(D[v][u]+D[u][w]<D[v][w]){
D[v][w]=D[v][u]+D[u][w];
for(int i=0;i!=G.vexnum;++i){
p[v][w][i]=p[v][u][i];}//v到u上的点也是v到w上的点
}
}}}
}
int main()
{
ifstream infile("rebuf.txt");
streambuf* backup=cin.rdbuf();//记录原状态
cin.rdbuf(infile.rdbuf());
Mgraph m;
createDG(m);
printgraph(m);
cout<<endl;
int p[3][3][3];//p[v][w][u]=true,则表示u为当前求得最短路径上的顶点,p起到记录到作用
int d[3][3];//实时跟新v到w的最短路径长度
Short_path_floyd(m,p,d);
cin.rdbuf(backup);
cout<<"请输入起点";
char x,y;
cin>>x;
int ix=locate(m,x);
cout<<"请输入终点";
cin>>y;
int iy=locate(m,y);
cout<<" "<<m.vexs[ix]<<"-->>"<<m.vexs[iy]<<" 长度:"<<"="<<" "<<d[ix][iy]<<" 路径:"<<m.vexs[ix]<<" ";
p[ix][iy][ix]=0;
p[ix][iy][iy]=0;
int tem=ix;
for(int i=0;i!=m.vexnum;++i){
if(p[ix][iy][i]==1&&yes(m,tem,i)){cout<<m.vexs[i]<<" ";p[ix][iy][i]=0;
tem=i;
i=0;}
}
cout<<m.vexs[iy]<<endl;
return 0;
}
rebuf.txt: 3 5
a b c
a b 5
a c 11
b a 6
b c 2
c a 3
书上图7.36
运行结果: