案例6-1.5 旅游规划 (25 分) 用邻接表实现Dijkstra算法
这题一开始做的时候没想到用邻接数组做,所以就用的链表。
总的来说还是Dijkstra算法,只不过是存储方式的问题罢了,我用了四个结构体,三个用来构建邻接表,是一层一层的关系,最后一个是做Dijkstra算法用的,具体注释我在做的时候为了检查也写了不少,应该能看懂吧,用优先队列应该还可以再改进,以后再改吧,现在有点勉强…立flag
Putout-list是我检查邻接表有没有建立,建立的数据会不会出错。
另外我没做主链表的内存回收…懒的搞,反正交了能过
提交图如下:
代码如下:
#include <stdio.h>
#include <cctype>
#include<cstring>
#include <cstdlib>
#include <iostream>
#include <string>
#include <queue>
using namespace std;
#define INFINITY 99999
typedef struct One_point *Linklist;
struct One_point //记录单个节点出度的相关节点数据
{
int city;
int legth;
int cost;
Linklist Next;
};
typedef struct City_Head *City;
struct City_Head//每个节点的每个头,每一个都包含这个节点的与其相连节点的各个信息
{
Linklist body;//相当于每一个链表的头
int city;
int link_number;
};
typedef struct Vertex_Head *Map;
struct Vertex_Head // 记录所有节点头的数据,将每一个链表的头整合!
{
City Head;
int Whole_edge;
int start;
int goal;
int Whole_number;
};
struct Dijk
{
int cost;
int legth;
};
Map Creat_Graph();//创建一个图,并初始化相关数据
void Input(Map p);//输入图的数据,完整的构建一个图
Linklist Creat_Node(int city,int legth,int cost);//返回一个单节点
void Insert_list(City_Head &head,Linklist Node);//将Node插入单节点中
void Putout_list(Map p);//输出全部数据,检查正确性
void Dijkstra(Map p);
int main(int argc, char const *argv[])
{
//freopen("F:\\测试数据\\数据结构学习与实验指导数据\\案例6-1.5 旅游规划.txt","r",stdin);
Map whole_city=Creat_Graph();
Input(whole_city);
Dijkstra(whole_city);
// Putout_list(whole_city);
system("pause");
return 0;
}
void Dijkstra(Map p)
{
bool *Visited=(bool*)malloc(sizeof(bool)*p->Whole_number);//记录是否经过
memset(Visited,0,sizeof(bool)*p->Whole_number);
Dijk *record=(Dijk*)malloc(sizeof(Dijk)*p->Whole_number);//记录最小值
// memset(record,INFINITY,sizeof(Dijk)*p->Whole_number);
for (int i = 0; i < p->Whole_number; i++)
record[i].cost=record[i].legth=INFINITY;
record[p->start].cost=record[p->start].legth=0;//起始位置的最优位置一定是0;
//下面就是正式的Dijkstra算法了:
while (true)
{
int i,minV=INFINITY,min;
for ( i = 0; i < p->Whole_number; i++)
if (!Visited[i])
break;
if (i == p->Whole_number)
break; //每次都检查一遍是不是全部点都已经纳入最优解了
for ( i = 0; i < p->Whole_number; i++)
{
if ((minV >= record[i].legth) && !Visited[i])
{
min=i;
minV=record[i].legth;
}//找到距离的最小值
}
Visited[min]=true;
//接下来找这个距离最小值的邻接点
int linklegth=record[min].legth;
int linkcost=record[min].cost;
for (Linklist temp=p->Head[min].body;temp; temp=temp->Next)
{
if (!Visited[temp->city])
{
if (record[temp->city].legth == (temp->legth+linklegth)&&
record[temp->city].cost > temp->cost+linkcost)
record[temp->city].cost=temp->cost+linkcost;
if (record[temp->city].legth > (temp->legth+linklegth))
{
record[temp->city].legth=temp->legth+linklegth;
record[temp->city].cost=temp->cost+linkcost;
}
}
}
}
cout << record[p->goal].legth << " " << record[p->goal].cost <<endl;
free(record);
free(Visited);
return;
}
void Insert_list(City_Head &head,Linklist Node)//这里必须传引用,不然修改不了,因为传的是形参,不用引用用Putout输出回发现链表是空的
{
Linklist Temp=head.body;
head.body=Node;
Node->Next=Temp;
}
void Input(Map p)
{
for (int i = 0; i < p->Whole_edge; i++)
{
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);//cin极有可能超时....
p->Head[a].link_number++;
p->Head[b].link_number++;
Linklist One_Node,Two_Node;
One_Node=Creat_Node(b,c,d);
Two_Node=Creat_Node(a,c,d);
Insert_list(p->Head[a],One_Node);
Insert_list(p->Head[b],Two_Node);
}
}
Map Creat_Graph()
{
Map whole_city=new Vertex_Head; //创建所有头节点的整合初始化
cin >> whole_city->Whole_number >>whole_city->Whole_edge
>> whole_city->start >> whole_city->goal;
whole_city->Head=new City_Head[whole_city->Whole_number];
memset(whole_city->Head,0,sizeof(City_Head)*whole_city->Whole_number);
for (int i = 0; i < whole_city->Whole_number; i++)
whole_city->Head[i].city=i;
return whole_city;
}
Linklist Creat_Node(int city,int legth,int cost)
{
Linklist p=new One_point;
p->cost=cost;
p->legth=legth;
p->city=city;
return p;
}
void Putout_list(Map p)
{
cout << "该图的边数和点数分别为:" << p->Whole_number<< " " << p->Whole_edge <<endl;
for (int i = 0; i < p->Whole_number; i++)
{
cout << "该链表的城市,连接城市的个数:" <<p->Head[i].city << " "<<p->Head[i].link_number<< endl;
Linklist temp=p->Head[i].body;
while (temp)
{
cout <<"与其相连的城市,长度和花销" <<temp->city<< " " << temp->legth << " " << temp->cost<<endl;
temp=temp->Next;
}
cout <<endl;
}
}