一、目的
1.熟悉算法设计的基本思想
2.掌握最小生成树算法的思路
二、内容与设计思想
川西风光几枚,以下图片是川西路线图。张三是旅游爱好者,他从成都出发自驾到西藏江达。
1)从成都到江达的最短自驾路线是什么?可以用Dijkstra算法来求解。
#include<bits/stdc++.h>
using namespace std;
#define Infinity 65535
#define ERROR -1
int P[10000];
string A[33]={"成都","都江堰","汶川","映秀","雅安","理县",
"日隆","马尔康","小金","泸定","康定","丹巴","金川",
"新都桥","塔公","八美","雅江","道孚","炉霍","翁达",
"A","B","壤塘","色达","甘孜","新龙","理塘",
"马尼干戈","新路海","德格","白玉","巴塘","江达"};
typedef struct GNode
{
int Nv;
int Ne;
int G[1000][1000];
int Data[1000];
} MGraph;
typedef struct ENode
{
int V1,V2;
int Weight;
} Edge;
MGraph* CreateGraph(int VertexNum)
{
int V,W;
MGraph* Graph;
Graph=new MGraph;
Graph->Nv=VertexNum;
Graph->Ne=0;
for (V=0;V<Graph->Nv;V++)
{
for (W=0;W<Graph->Nv;W++)
{
Graph->G[V][W]=Infinity;
}
}
return Graph;
}
void InsertEdge(MGraph* Graph,Edge* E)
{
Graph->G[E->V1-Graph->Data[0]][E->V2-Graph->Data[0]]=E->Weight;
Graph->G[E->V2-Graph->Data[0]][E->V1-Graph->Data[0]]=E->Weight;
}
MGraph* BuildGraph(MGraph* Graph)
{
Edge* E;
int V;
int Nv,Ne,i;
cin>>Nv>>Ne;
Graph=CreateGraph(Nv);
Graph->Ne=Ne;
for (V=0;V<Nv;V++)
{
// cin>>Graph->Data[V];
Graph->Data[V]=V;
}
if (Graph->Ne!=0)
{
E=new Edge;
for (i=0;i<Graph->Ne;i++)
{
cin>>E->V1>>E->V2>>E->Weight;
InsertEdge(Graph,E);
}
}
cout<<endl;
return Graph;
}
int FindMinDist(MGraph* Graph,int dist[],int collected[])
{
int MinV,V;
int MinDist=Infinity;
for (V=0;V<Graph->Nv;V++)
{
if (collected[V]==false&&dist[V]<MinDist)
{
MinDist=dist[V];
MinV=V;
}
}
if (MinDist<Infinity)
{
return MinV;
}
else
{
return ERROR;
}
}
bool Dijkstra(MGraph* Graph,int dist[],int path[],int S)
{
int collected[100000];
int V,W;
for (V=0;V<Graph->Nv;V++)
{
dist[V]=Graph->G[S][V];
if (dist[V]<Infinity)
{
path[V]=S;
}
else
{
path[V]=-1;
}
collected[V]=false;
}
dist[S]=0;
collected[S]=true;
while (1)
{
V=FindMinDist(Graph,dist,collected);
if (V==ERROR)
{
break;
}
collected[V]=true;
for (W=0;W<Graph->Nv;W++)
{
if (collected[W]==false&&Graph->G[V][W]<Infinity)
{
if (Graph->G[V][W]<0)
{
return false;
}
if (dist[V]+Graph->G[V][W]<dist[W])
{
dist[W]=dist[V]+Graph->G[V][W];
path[W]=V;
}
}
}
}
return true;
}
int FindPath(int path[],int V)
{
int k=0;
while (V>=0)
{
P[k]=V;
V=path[V];
k++;
}
return k;
}
int main()
{
MGraph* Graph;
bool flag;
int S,E,Total;
int dist[100000],path[100000];
S=0;
E=32;
Graph=BuildGraph(Graph);
flag=Dijkstra(Graph,dist,path,S);
if (flag==true)
{
cout<<A[S]<<"-->"<<A[E]<<";"<<dist[E]<<endl;
}
Total=FindPath(path,E);
for (int i=Total-1;i>=0;i--)
{
cout<<A[P[i]]<<" ";
}
return 0;
}
2)张三把理塘列为必游之地。怎么规划路线,使得总行程最短?
#include<bits/stdc++.h>
using namespace std;
#define Infinity 65535
#define ERROR -1
int P[100000];
string A[33]={"成都","都江堰","汶川","映秀","雅安","理县",
"日隆","马尔康","小金","泸定","康定","丹巴","金川",
"新都桥","塔公","八美","雅江","道孚","炉霍","翁达",
"A","B","壤塘","色达","甘孜","新龙","理塘",
"马尼干戈","新路海","德格","白玉","巴塘","江达"};
typedef struct GNode
{
int Nv;
int Ne;
int G[1000][1000];
int Data[1000];
} MGraph;
typedef struct ENode
{
int V1,V2;
int Weight;
} Edge;
MGraph* CreateGraph(int VertexNum)
{
int V,W;
MGraph* Graph;
Graph=new MGraph;
Graph->Nv=VertexNum;
Graph->Ne=0;
for (V=0;V<Graph->Nv;V++)
{
for (W=0;W<Graph->Nv;W++)
{
Graph->G[V][W]=Infinity;
}
}
return Graph;
}
void InsertEdge(MGraph* Graph,Edge* E)
{
Graph->G[E->V1-Graph->Data[0]][E->V2-Graph->Data[0]]=E->Weight;
Graph->G[E->V2-Graph->Data[0]][E->V1-Graph->Data[0]]=E->Weight;
}
MGraph* BuildGraph(MGraph* Graph)
{
Edge* E;
int V;
int Nv,Ne,i;
cin>>Nv>>Ne;
Graph=CreateGraph(Nv);
Graph->Ne=Ne;
for (V=0;V<Nv;V++)
{
// cin>>Graph->Data[V];
Graph->Data[V]=V;
}
if (Graph->Ne!=0)
{
E=new Edge;
for (i=0;i<Graph->Ne;i++)
{
cin>>E->V1>>E->V2>>E->Weight;
InsertEdge(Graph,E);
}
}
cout<<endl;
return Graph;
}
int FindMinDist(MGraph* Graph,int dist[],int collected[])
{
int MinV,V;
int MinDist=Infinity;
for (V=0;V<Graph->Nv;V++)
{
if (collected[V]==false&&dist[V]<MinDist)
{
MinDist=dist[V];
MinV=V;
}
}
if (MinDist<Infinity)
{
return MinV;
}
else
{
return ERROR;
}
}
bool Dijkstra(MGraph* Graph,int dist[],int path[],int S)
{
int collected[100000];
int V,W;
for (V=0;V<Graph->Nv;V++)
{
dist[V]=Graph->G[S][V];
if (dist[V]<Infinity)
{
path[V]=S;
}
else
{
path[V]=-1;
}
collected[V]=false;
}
dist[S]=0;
collected[S]=true;
while (1)
{
V=FindMinDist(Graph,dist,collected);
if (V==ERROR)
{
break;
}
collected[V]=true;
for (W=0;W<Graph->Nv;W++)
{
if (collected[W]==false&&Graph->G[V][W]<Infinity)
{
if (Graph->G[V][W]<0)
{
return false;
}
if (dist[V]+Graph->G[V][W]<dist[W])
{
dist[W]=dist[V]+Graph->G[V][W];
path[W]=V;
}
}
}
}
return true;
}
int FindPath(int path[],int V)
{
int k=0;
while (V>=0)
{
P[k]=V;
V=path[V];
k++;
}
return k;
}
int main()
{
MGraph* Graph;
bool flag;
int S,M,E,Total;
int dist[100000],path[100000];
S=0;
M=26;
E=32;
Graph=BuildGraph(Graph);
flag=Dijkstra(Graph,dist,path,S);
if (flag==true)
{
cout<<A[S]<<"-->"<<A[M]<<";"<<dist[M]<<endl;
}
int Total1=FindPath(path,M);
for (int i=Total1-1;i>=0;i--)
{
cout<<A[P[i]]<<" ";
}
cout<<endl;
flag=Dijkstra(Graph,dist,path,M);
if (flag==true)
{
cout<<A[M]<<"-->"<<A[E]<<";"<<dist[E]<<endl;
}
int Total2=FindPath(path,E);
for (int i=Total2-1;i>=0;i--)
{
cout<<A[P[i]]<<" ";
}
return 0;
}
3)张三觉得理塘风景很美,道孚也不错,两个地方如果能够去一个地方的话就心满意足了。应该怎么安排行程使得总行程最短?
4)张三在规划线路的时候,发现不同路况行驶速度不一样。地图中粗的路径表示平均时速可以达到80公里每小时,而细的路径表示平均时速仅仅有每小时60公里每小时。那么用时最短的路径是哪一条?
#include<bits/stdc++.h>
using namespace std;
#define Infinity 65535
#define ERROR -1
int P[10000];
string A[33]={"成都","都江堰","汶川","映秀","雅安","理县",
"日隆","马尔康","小金","泸定","康定","丹巴","金川",
"新都桥","塔公","八美","雅江","道孚","炉霍","翁达",
"A","B","壤塘","色达","甘孜","新龙","理塘",
"马尼干戈","新路海","德格","白玉","巴塘","江达"};
typedef struct GNode
{
int Nv;
int Ne;
double G[1000][1000];
int Data[1000];
// int T[1000][1000];
} MGraph;
typedef struct ENode
{
int V1,V2;
double Weight;
int T;
} Edge;
MGraph* CreateGraph(int VertexNum)
{
int V,W;
MGraph* Graph;
Graph=new MGraph;
Graph->Nv=VertexNum;
Graph->Ne=0;
for (V=0;V<Graph->Nv;V++)
{
for (W=0;W<Graph->Nv;W++)
{
Graph->G[V][W]=Infinity;
}
}
return Graph;
}
void InsertEdge(MGraph* Graph,Edge* E)
{
if (E->T==0)
{
Graph->G[E->V1-Graph->Data[0]][E->V2-Graph->Data[0]]=E->Weight/60.0;
Graph->G[E->V2-Graph->Data[0]][E->V1-Graph->Data[0]]=E->Weight/60.0;
}
else if (E->T==1)
{
Graph->G[E->V1-Graph->Data[0]][E->V2-Graph->Data[0]]=E->Weight/80.0;
Graph->G[E->V2-Graph->Data[0]][E->V1-Graph->Data[0]]=E->Weight/80.0;
}
}
//void Time(MGraph* Graph)
//{
// int V,W;
// for (V=0;V<33;V++)
// {
// for (W=0;W<33;W++)
// {
// if (Graph->T[V][W]==0)
// {
// Graph->G[V][W]=Graph->G[V][W]/60;
// }
// else if (Graph->T[V][W]==1)
// {
// Graph->G[V][W]=Graph->G[V][W]/80;
// }
// }
// }
//}
MGraph* BuildGraph(MGraph* Graph)
{
Edge* E;
int V;
int Nv,Ne,i;
cin>>Nv>>Ne;
Graph=CreateGraph(Nv);
Graph->Ne=Ne;
for (V=0;V<Nv;V++)
{
// cin>>Graph->Data[V];
Graph->Data[V]=V;
}
if (Graph->Ne!=0)
{
E=new Edge;
for (i=0;i<Graph->Ne;i++)
{
cin>>E->V1>>E->V2>>E->Weight>>E->T;
InsertEdge(Graph,E);
// Time(Graph);
}
}
cout<<endl;
return Graph;
}
int FindMinDist(MGraph* Graph,double dist[],int collected[])
{
int MinV,V;
int MinDist=Infinity;
for (V=0;V<Graph->Nv;V++)
{
if (collected[V]==false&&dist[V]<MinDist)
{
MinDist=dist[V];
MinV=V;
}
}
if (MinDist<Infinity)
{
return MinV;
}
else
{
return ERROR;
}
}
bool Dijkstra(MGraph* Graph,double dist[],int path[],int S)
{
int collected[100000];
int V,W;
for (V=0;V<Graph->Nv;V++)
{
dist[V]=Graph->G[S][V];
if (dist[V]<Infinity)
{
path[V]=S;
}
else
{
path[V]=-1;
}
collected[V]=false;
}
dist[S]=0;
collected[S]=true;
while (1)
{
V=FindMinDist(Graph,dist,collected);
if (V==ERROR)
{
break;
}
collected[V]=true;
for (W=0;W<Graph->Nv;W++)
{
if (collected[W]==false&&Graph->G[V][W]<Infinity)
{
if (Graph->G[V][W]<0)
{
return false;
}
if (dist[V]+Graph->G[V][W]<dist[W])
{
dist[W]=dist[V]+Graph->G[V][W];
path[W]=V;
}
}
}
}
return true;
}
int FindPath(int path[],int V)
{
int k=0;
while (V>=0)
{
P[k]=V;
V=path[V];
k++;
}
return k;
}
int main()
{
MGraph* Graph;
bool flag;
int S,E,Total;
int path[100000];
double dist[100000];
S=0;
E=32;
Graph=BuildGraph(Graph);
flag=Dijkstra(Graph,dist,path,S);
if (flag==true)
{
cout<<A[S]<<"-->"<<A[E]<<";"<<dist[E]<<endl;
}
Total=FindPath(path,E);
for (int i=Total-1;i>=0;i--)
{
cout<<A[P[i]]<<" ";
}
return 0;
}
5)(思考题)考虑到Dijkstra算法仅仅从一段开始寻找路径,效率不高。李教授想到一个高招,就是同时从出发地和目的地进行搜索,扩展搜索节点,然后两个方向扩展的路径会在中途相遇,则拼接起来的路径就是最短路径。如何实现李教授这个想法?
三、使用环境
推荐使用C/C++集成编译环境。
四、实验过程
1、编写相关实验代码
2、写出算法的思路。
第二题分成两步,先由成都到理塘再从理塘到江达,用两次Dijkstra算法;
第三题即把1、2题的距离比较;
第四题再设置一个数组E->T,当值为0时代表细边,当值为1时代表粗边,然后把G[V][W]的值换算成时间再使用Dijkstra算法。