[C] 图的广度优先搜索——最少转机

我一直认为用C语言来描述数据结构(尤其是这种简单的)是一个非常不错的方式。

C语言在表示数据,存取数据,表现数据结构里都没有那么多“捷径”可以走,所以用C语言写基础的数据结构的代码,是非常方便读者理解的。

毕竟,C语言极有可能成为一个程序员的入门语言。

题目描述

在这里插入图片描述
小哼和小哈一同坐飞机去旅游,他们现在位于1号城市,目标是5号城市,可是1号城市并没有到5号城市的直航。不过小哼已经收集了很多航班的信息,现在小哼希望找到一种乘坐方式,使得转机的次数最少,如何解决呢?

在这里插入图片描述

输入:

5 7 1 5
1 2
1 3
2 3
2 4
3 4
3 5
4 5

输出

2

题解

这是一个典型的广度优先查找,查找从A点到B点的最少转机次数。

一开始不喜欢DFS,喜欢BFS,觉得递归实在是太复杂了。做完这题发现,BFS要理解好那个存储状态的队列也不容易。比如下面代码的que里面的s,在数组里每个s会是什么样子的呢?s什么时候+1呢?+1的时候是基于什么的呢?这里逻辑就有点绕了。

不过机智的我还是弄明白了,对于每次s要+1的时候,取决于现在的头指针指向的哪个点(即本次转机的出发机场是哪里)。

最后,输出尾指针-1(因为尾指针每次都要++以指向下一个空格子)里的s属性的值就可以。

具体可以看代码。

#include<stdio.h>
int a[2000][2000], book[2000];

struct note
{
    int x;//城市编号
    int s;//转机次数
};
struct note que[2000];


int main()
{
    int i, j, n, m, x, y, start, end;
    int cur, head, tail;
    scanf("%d %d %d %d", &n, &m, &start, &end);
    for (i = 1; i <= n; i++)
        for (j = 1; j <= n; j++)
            if (i == j)
                a[i][j] = 0;
            else
                a[i][j] = 99999999;

    for (i = 1; i <= m; i++)
    {
        scanf("%d %d", &x, &y);
        a[x][y] = 1;
        a[y][x] = 1;
    }
    head = 1;
    tail = 1;

    que[tail].x = start;
    que[tail].s = 0;
    book[1] = start;
    tail++;

    int flag = 0;

    while (head < tail)
    {
        //当前正在访问的顶点的编号
        cur = que[head].x;
        // 从1~n进行尝试
        for (i = 1; i <= n; i++)
        {
            if (a[cur][i] != 99999999 && book[i] == 0)
            {
                que[tail].x = i;
                que[tail].s = que[head].s + 1; //转机次数+1,基于的是头指针下的s
                tail++;
                book[i] = 1;
            }
            //如果tail>n则表示所有顶点都被访问过
            if (que[tail].x == n)
            {
                flag = 1;
                break;
            }
        }
        if (flag == 1)
            break;
        //这里不要忘记,拓展完之后,要将头指针+1
        head++;
    }

    printf("%d ", que[tail - 1].s);
    return 0;
}

输出结果:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
深度优先搜索和广度优先搜索论中的两个基本算法,它们在C语言中的实现方式如下: 深度优先搜索(DFS):深度优先搜索是一种递归的算法,它从的某个顶点开始遍历,尽可能深地搜索的分支,直到不能再继续为止,然后回溯到前一个节点,继续搜索其他分支。在C语言中,可以使用邻接矩阵或邻接表来表示,然后使用递归函数来实现深度优先搜索。 ``` #define MAX_VERTEX_NUM 100 // 最大顶点数 typedef struct { int vertex[MAX_VERTEX_NUM]; // 顶点数组 int edge[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 邻接矩阵 int vertex_num, edge_num; // 顶点数和边数 } Graph; void DFS(Graph *G, int v, int visited[]) { visited[v] = 1; // 标记当前节点已访问 printf("%d ", G->vertex[v]); // 输出当前节点 for (int i = 0; i < G->vertex_num; i++) { if (G->edge[v][i] && !visited[i]) { // 如果当前节点与下一个节点有边且下一个节点未被访问 DFS(G, i, visited); // 递归访问下一个节点 } } } int main() { Graph G = { {1, 2, 3, 4, 5}, // 顶点数组 { {0, 1, 1, 0, 0}, {1, 0, 0, 1, 1}, {1, 0, 0, 1, 0}, {0, 1, 1, 0, 1}, {0, 1, 0, 1, 0} }, // 邻接矩阵 5, 7 // 顶点数和边数 }; int visited[MAX_VERTEX_NUM] = {0}; // 初始化所有节点未被访问 DFS(&G, 0, visited); // 从第一个节点开始深度优先搜索 return 0; } ``` 广度优先搜索(BFS):广度优先搜索是一种迭代的算法,它从的某个顶点开始遍历,先访问该顶点的所有邻居节点,然后依次访问邻居节点的邻居节点,直到遍历完整个。在C语言中,可以使用邻接矩阵或邻接表来表示,然后使用队列来实现广度优先搜索。 ``` #define MAX_VERTEX_NUM 100 // 最大顶点数 typedef struct { int vertex[MAX_VERTEX_NUM]; // 顶点数组 int edge[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 邻接矩阵 int vertex_num, edge_num; // 顶点数和边数 } Graph; void BFS(Graph *G, int v, int visited[]) { int queue[MAX_VERTEX_NUM], front = 0, rear = 0; // 定义队列 visited[v] = 1; // 标记当前节点已访问 printf("%d ", G->vertex[v]); // 输出当前节点 queue[rear++] = v; // 将当前节点入队 while (front != rear) { // 队列不为空时循环 int w = queue[front++]; // 取出队首节点 for (int i = 0; i < G->vertex_num; i++) { if (G->edge[w][i] && !visited[i]) { // 如果当前节点与下一个节点有边且下一个节点未被访问 visited[i] = 1; // 标记下一个节点已访问 printf("%d ", G->vertex[i]); // 输出下一个节点 queue[rear++] = i; // 将下一个节点入队 } } } } int main() { Graph G = { {1, 2, 3, 4, 5}, // 顶点数组 { {0, 1, 1, 0, 0}, {1, 0, 0, 1, 1}, {1, 0, 0, 1, 0}, {0, 1, 1, 0, 1}, {0, 1, 0, 1, 0} }, // 邻接矩阵 5, 7 // 顶点数和边数 }; int visited[MAX_VERTEX_NUM] = {0}; // 初始化所有节点未被访问 BFS(&G, 0, visited); // 从第一个节点开始广度优先搜索 return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值