一、概述
本题属于数据结构中图的部分,中心思想是利用dijkstra算法,找到源点和目标点的最短路径数量。输出最短路径数量以及一条路径上可供调遣的最大人数。核心问题是理解dijkstra算法的应用。理论部分十分容易理解,在源点周围找到第一个距离最短的点,更新再找第二个第三个,手动模拟很方便,但是转换为代码没那么简单。第二是如何找到最短路径的条数以及最大人数,这需要在原算法的基础上改进,还是不那么简单的,至少我做了好久。
二、分析
1、准备工作
主要是录入题干数据。
采用两个函数,创造新图以及打印图。
如下:
数据结构
比一般的图多了两个元素,即源点和目标点。
typedef struct {
VertexType vexs[Max];
EdgeType arc[Max][Max];
int vnum, edgenum;
int source, desti;
}Mgraphy;
这是创造图的函数。
要注意首先将整个图的邻接矩阵初始化。然后录入数据。
void CreateGraphy(Mgraphy *G)
{
scanf("%d", &G->vnum);
scanf("%d", &G->edgenum);
scanf("%d", &G->source);
scanf("%d", &G->desti);
int i = 0;
for (i = 0; i < G->vnum; i++)
scanf("%d", &G->vexs[i]);
int j = 0;
for (i = 0; i < G->edgenum; i++)
for (j = 0; j < G->edgenum; j++)
G->arc[i][j] = Infinite;
int row, line,length;
for (i = 0; i < G->edgenum; i++)
{
scanf("%d %d", &row, &line);
scanf("%d", &length);
G->arc[row][line] = length;
G->arc[line][row] = length;
}
}
这是打印图的函数。
没什么用,我只打印了邻接矩阵,在上传的时候还要注释掉,只是debug的时候方便点。
void PrintGraphy(Mgraphy *G)
{
int i, j;
for (i = 0; i < G->edgenum; i++)
{
for (j = 0; j < G->edgenum; j++)
printf("%d ", G->arc[i][j]);
printf("\n");
}
}
2、dijsktra函数
本题核心部分。该函数的最主要工作是对两个数组进行操作。其一是最短路径数组sqtable,其二是访问数组final。
前者用于记录源点到各点的最短路径,这是其最重要的特点,后者用于记录哪些点已访问,哪些点未访问。整个函数的工作流程如下:
①函数数组初始化。数组元素都置为0,注意不要用{0},pta服务器不认,报错,用memset函数。然后将源点连接的点的弧长填入sqtable,此时满足sqtable的特点。
②进入主循环,循环次数为总的节点数量。
主循环内的小循环一,用于挑选出sqtable中的最小的第k个节点,并将final中对应值置为1。这代表着从源点到第k个节点的最短路径已找到。
既然已找到一个新的最短路径节点,那么可能会出现新的节点,原有节点的距离也可能不再是最小的,其特点被破坏。这样一来,整个sqtable可能需要更新。
进入小循环二。找到满足以下条件的节点:
最短路径还未找到且由于k的存在,从源点到k加上从k到该点(w)的距离和小于从源点到w的距离。这说明出现了新的更优路径,则将该路径和代替原值填入sqtable。即:经过小循环二后,sqtable再次满足它的特点。
既然sqtable已更新,那么小循环一即可找到新的最小路径。由此直到大循环循环完毕,final的值全为1,sqtable存储所有最短路径(对于连通图来说)。