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;
}`

大部分照着程杰老师《大话数据结构》的源代码的第七章图里边邻接表的广度遍历写的,很详细,可以去看一下

posted @ 2025-04-28 00:35  sirro1uta  阅读(33)  评论(0)    收藏  举报