CSES 1667 (图,BFS 输出最短路径)
题目如下

题目分析
寻找最短路径,输入给我们的是每个节点和他的下一个节点,那么我们就据此来创建一个邻接表,在在邻接表中展开广度遍历,寻找从1到目标电脑的最短路径。
创建邻接表,先来定义一下结构体
`typedef struct EdgeNode {/* 边表结点 /
int adjvex; / 邻接点域,存储该顶点对应的下标 */
struct EdgeNode next; / 链域,指向下一个邻接点 */
}EdgeNode;
typedef struct VertexNode{; /* 顶点表结点 */
EdgeNode firstedge;/ 边表头指针 */
}VertexNode, AdjList[MAXN];
typedef struct{
AdjList adjList; /* 所有顶点+所有边的总集合/
int numVertexes,numEdges; / 图中当前顶点数和边数 /
}graphAdjList,GraphAdjList; /* 本体 & 指针 */`
创建邻接表
void CreateGraph(GraphAdjList *G, int n, int m) { *G = (GraphAdjList) malloc(sizeof(graphAdjList)); // 分配内存 (*G)->numVertexes = n; // 顶点数量 (*G)->numEdges = m; // 边数量 for (int i = 1; i <= n; i++) { (*G)->adjList[i].firstedge = NULL; // 每个顶点的边表初始化为空 } for (int i = 0; i < m; i++) { int a, b; scanf("%d%d", &a, &b); /* b->a */ EdgeNode *e1 =(EdgeNode *)malloc(sizeof(EdgeNode)); e1->adjvex = b; e1->next = (*G)->adjList[a].firstedge; // 当前a的边表头接到e的next上 (*G)->adjList[a].firstedge = e1; // a的边表头指向新的e /* a->b */ EdgeNode *e2 =(EdgeNode *)malloc(sizeof(EdgeNode)); e2->adjvex = a; e2->next =(*G)->adjList[b].firstedge; (*G)->adjList[b].firstedge = e2; } }
因为我们建立的是无向图,无论是从 a 走到 b,还是从 b 走到 a,都要能正常遍历!
对邻接表进行BFS广度遍历时,我们初始化新的数组path用于记录路径,对其进行回溯的操作,从end开始不断反推来时的路径直到回到起点,记录这条路径并输出
然后遍历当前节点 u 的所有邻居节点,然后把没有走过的邻居节点加到队列里去
for (EdgeNode *p = G->adjList[u].firstedge; p; p = p->next) { int v = p->adjvex; if (!visited[v]) { visited[v] = 1; pre[v] = u; queue[rear++] = (Node){v, now.step + 1}; } }
完整代码如下`#include
include <stdio.h>
include <stdlib.h>
include <string.h>
using namespace std;
define MAXN 200002
typedef struct EdgeNode {/* 边表结点 /
int adjvex; / 邻接点域,存储该顶点对应的下标 */
struct EdgeNode next; / 链域,指向下一个邻接点 */
}EdgeNode;
typedef struct VertexNode{; /* 顶点表结点 */
EdgeNode firstedge;/ 边表头指针 */
}VertexNode, AdjList[MAXN];
typedef struct{
AdjList adjList; /* 所有顶点+所有边的总集合/
int numVertexes,numEdges; / 图中当前顶点数和边数 /
}graphAdjList,GraphAdjList; /* 本体 & 指针 */
typedef struct{
int pos; //当前位置
int step; //当前累计步数
}Node;
int visited[MAXN];
int pre[MAXN]; //记录路径
void CreateGraph(GraphAdjList G, int n, int m) {
G = (GraphAdjList) malloc(sizeof(graphAdjList)); // 分配内存
(G)->numVertexes = n; // 顶点数量
(G)->numEdges = m; // 边数量
for (int i = 1; i <= n; i++) {
(G)->adjList[i].firstedge = NULL; // 每个顶点的边表初始化为空
}
for (int i = 0; i < m; i++) {
int a, b;
scanf("%d%d", &a, &b);
/ b->a /
EdgeNode e1 =(EdgeNode )malloc(sizeof(EdgeNode));
e1->adjvex = b;
e1->next = (G)->adjList[a].firstedge; // 当前a的边表头接到e的next上
(G)->adjList[a].firstedge = e1; // a的边表头指向新的e
/ a->b */
EdgeNode e2 =(EdgeNode )malloc(sizeof(EdgeNode));
e2->adjvex = a;
e2->next =(G)->adjList[b].firstedge;
(G)->adjList[b].firstedge = e2;
}
}
void BFS(GraphAdjList G, int start, int end){
memset(visited, 0, sizeof(visited)); //把 visited 数组里的所有元素全部初始化为 0;
memset(pre, -1, sizeof(pre));
Node queue[MAXN];
int front = 0, rear = 0;
queue[rear++] = (Node){start, 1}; /*步数包含起点*/
visited[start] = 1;
while(front < rear){
Node now = queue[front++];
int u = now.pos;
if (u == end) { /*回溯*/
printf("%d\n", now.step);
int path[MAXN], cnt = 0;
int p = end;
while (p != -1) {
path[cnt++] = p; /*pre[新节点] = 当前节点*/
p = pre[p]; /*更新 p,让 p 指向它的前一个点*/
}
for (int i = cnt - 1; i >= 0; i--) {
printf("%d ", path[i]);
}
printf("\n");
return;
}
for (EdgeNode *p = G->adjList[u].firstedge; p; p = p->next) {
int v = p->adjvex;
if (!visited[v]) {
visited[v] = 1;
pre[v] = u;
queue[rear++] = (Node){v, now.step + 1};
}
}
}
printf("IMPOSSIBLE\n");
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
GraphAdjList G;
CreateGraph(&G, n, m);
BFS(G, 1, n);
return 0;
}`
大部分照着程杰老师《大话数据结构》的源代码的第七章图里边邻接表的广度遍历写的,很详细,可以去看一下

浙公网安备 33010602011771号