图的广度优先遍历 - 最少转机

2023-11-02 19:10

本文主要是介绍图的广度优先遍历 - 最少转机,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

图的广度优先遍历 - 最少转机

现在位于 1 号城市,目标是 5 号城市,可是 1 号城市并没有到 5 号城市的直航。现在我们希望找到一种乘坐方式,使得转机的次数最少。

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

在这里插入图片描述

第一行的 5 表示有 5 个城市 (城市编号为 1~5),7 表示有 7 条航线,1 表示起点城市,5 表示目标城市,接下来 7 行每行是一条类似 a b 这样的数据表示城市 a 和城市 b 之间有航线,也就是说城市 a 和城市 b 之间可以相互到达。

input.txt 第一行是测试用例个数 2,后续依次为具体测试用例数据。

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

这里我们还是使用邻接矩阵来存储图,需要注意的是这里是无向图。城市的编号就是图的顶点,而航班则是两顶点之间的边。要求的是转机次数最少,所以我们可以认为所有边的长度都是 1。下面我们用广度优先搜索来解决这个问题。

首先将 1 号城市入队,通过 1 号城市我们可以到达 (扩展出) 2 号和 3 号城市。2 号城市又可以扩展出 3 号城市和 4 号城市。因为 3 号城市已经在队列中,所以只需将 4 号城市入队。接下来 3 号城市又可以扩展出 4 号城市和 5 号城市,因为 4 号城市也已经在队列中,所以只需将 5 号城市入队,此时已经找到了目标城市 5 号城市,算法结束。

在这里插入图片描述

可以输入以下数据进行验证,

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

运行结果是:

2

当然也可以使用深度优先捜索解决,但是这里用广度优先搜索会更快。广度优先搜索更加适用于所有边的权值相同的情况。

/*
============================================================================
Name        : yongqiang.cpp
Author      : Yongqiang Cheng
Version     : Version 1.0.0
Copyright   : Copyright (c) 2020 Yongqiang Cheng
Description : Hello World in C++, Ansi-style
============================================================================
*/#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <time.h>using namespace std;
/*
void dfs(int data[100][100], int N, int cur, int des, int book[100], int dist, int *min_dist)
{// cur 是当前所在城市的编号 - 1// dist 是当前已经走过的路程// 如果当前走过的路程己经大于之前找到的最短路程,则没有必要再往下尝试了,立即返回if (dist > *min_dist) {return;}// 判断是否到达了目标城市if (cur == des) {if (dist < *min_dist) { *min_dist = dist; } // 更新最小值return;}// 从 1 (1 - 1) 号城市到 N (N - 1) 号城市的尝试for (int k = 0; k < N; k++){// 判断当前城市 cur 到城市 k 是否有路,并判断城市 k 是否在已经走过的路径中if ((0 == book[k]) && (data[cur][k] != INT_MAX)){book[k] = 1; // 标记城市 k 已经在路径中dfs(data, N, k, des, book, dist + data[cur][k], min_dist); // 从城市 k 再出发,继续寻找目标城市book[k] = 0; // 之前一步探索完毕之后,取消对城市 k 的标记}}return;
}
*/int inference(int map[50][2], int N, int M, int start, int end)
{int ret = 0;int data[50][50] = { 0 };int book[50] = { 0 };// 初始化二维矩阵for (int i = 0; i < N; i++){for (int j = 0; j < N; j++){if (i == j) {data[i][j] = 0;}else {data[i][j] = INT_MAX;}}}// 读入城市之间的道路// 无向图for (int m = 0; m < M; m++){int h = map[m][0] - 1;int w = map[m][1] - 1;data[h][w] = 1;data[w][h] = 1;}start -= 1;end -= 1;int que[2500][2] = { 0 };int head = 0, tail = 0;int flag = 0;int step = 0;int min_step = 0;// 从 start 号城市出发,将 start 号城市加入队列que[tail][0] = start;que[tail][1] = step;tail++;// 标记 start 号城市已在队列中book[start] = 1;// 当队列不为空的时候循环while (head < tail){// 当前队列中首城市的编号int popt = que[head][0];int cur_step = que[head][1];head++;// 从 1~N 依次尝试for (int k = 0; k < N; k++){// 城市 popt 到城市 k 是否有航班并且判断城市 k 是否已经在队列中if ((0 == book[k]) && (data[popt][k] != INT_MAX)){// 城市 popt 到城市 k 是有航班并且判断城市 k 不在队列中,将 k 号城市入队que[tail][0] = k;que[tail][1] = cur_step + 1; // 转机次数 + 1tail++;book[k] = 1; // 标记城市 k 已经在}// 如果到达目标城市,停止扩展,任务结束,退出循环if (que[tail - 1][0] == end) {flag = 1;min_step = cur_step + 1;break;}}if (1 == flag){break;}}ret = min_step;return ret;
}int main()
{clock_t start = 0, end = 0;double cpu_time_used = 0;const char input_txt[] = "D:\\visual_studio_workspace\\yongqiangcheng\\yongqiangcheng\\input.txt";const char output_txt[] = "D:\\visual_studio_workspace\\yongqiangcheng\\yongqiangcheng\\output.txt";freopen(input_txt, "r", stdin);// freopen(output_txt, "w", stdout);start = clock();printf("Start of the program, start = %ld\n", start);printf("Start of the program, start = %ld\n\n", start);int case_num;cin >> case_num;for (int i = 1; i <= case_num; i++){int N = 0, M = 0, start = 0, end = 0;int map[50][2] = { 0 };cin >> N >> M >> start >> end;for (int h = 0; h < M; h++){for (int w = 0; w < 2; w++){cin >> map[h][w];}}int ret = inference(map, N, M, start, end);cout << "CASE #" << i << " = " << ret << endl;}end = clock();printf("\nEnd of the program, end = %ld\n", end);printf("End of the program, end = %ld\n", end);cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;printf("Total time taken by CPU: %f\n", cpu_time_used);printf("Exiting of the program...\n");fclose(stdin);// fclose(stdout);return 0;
}
Start of the program, start = 0
Start of the program, start = 0CASE #1 = 2
CASE #2 = 2End of the program, end = 6
End of the program, end = 6
Total time taken by CPU: 0.006000
Exiting of the program...
请按任意键继续. . .

在这里插入图片描述

References

《啊哈!算法》 - 啊哈磊

这篇关于图的广度优先遍历 - 最少转机的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/332679

相关文章

hdu1180(广搜+优先队列)

此题要求最少到达目标点T的最短时间,所以我选择了广度优先搜索,并且要用到优先队列。 另外此题注意点较多,比如说可以在某个点停留,我wa了好多两次,就是因为忽略了这一点,然后参考了大神的思想,然后经过反复修改才AC的 这是我的代码 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<

poj 3190 优先队列+贪心

题意: 有n头牛,分别给他们挤奶的时间。 然后每头牛挤奶的时候都要在一个stall里面,并且每个stall每次只能占用一头牛。 问最少需要多少个stall,并输出每头牛所在的stall。 e.g 样例: INPUT: 51 102 43 65 84 7 OUTPUT: 412324 HINT: Explanation of the s

poj 2431 poj 3253 优先队列的运用

poj 2431: 题意: 一条路起点为0, 终点为l。 卡车初始时在0点,并且有p升油,假设油箱无限大。 给n个加油站,每个加油站距离终点 l 距离为 x[i],可以加的油量为fuel[i]。 问最少加几次油可以到达终点,若不能到达,输出-1。 解析: 《挑战程序设计竞赛》: “在卡车开往终点的途中,只有在加油站才可以加油。但是,如果认为“在到达加油站i时,就获得了一

POJ2010 贪心优先队列

c头牛,需要选n头(奇数);学校总共有f的资金, 每头牛分数score和学费cost,问合法招生方案中,中间分数(即排名第(n+1)/2)最高的是多少。 n头牛按照先score后cost从小到大排序; 枚举中间score的牛,  预处理左边与右边的最小花费和。 预处理直接优先队列贪心 public class Main {public static voi

leetcode105 从前序与中序遍历序列构造二叉树

根据一棵树的前序遍历与中序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如,给出 前序遍历 preorder = [3,9,20,15,7]中序遍历 inorder = [9,3,15,20,7] 返回如下的二叉树: 3/ \9 20/ \15 7   class Solution {public TreeNode buildTree(int[] pr

深度优先(DFS)和广度优先(BFS)——算法

深度优先 深度优先搜索算法(英语:Depth-First-Search,DFS)是一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支,当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访

PHP实现二叉树遍历(非递归方式,栈模拟实现)

二叉树定义是这样的:一棵非空的二叉树由根结点及左、右子树这三个基本部分组成,根据节点的访问位置不同有三种遍历方式: ① NLR:前序遍历(PreorderTraversal亦称(先序遍历)) ——访问结点的操作发生在遍历其左右子树之前。 ② LNR:中序遍历(InorderTraversal) ——访问结点的操作发生在遍历其左右子树之中(间)。 ③ LRN:后序遍历(PostorderT

react笔记 8-17 属性绑定 class绑定 引入图片 循环遍历

1、绑定属性 constructor(){super()this.state={name:"张三",title:'我是一个title'}}render() {return (<div><div>aaaaaaa{this.state.name}<div title={this.state.title}>我是一个title</div></div></div>)} 绑定属性直接使用花括号{}   注

【IT】软件行业发展的前瞻性和希望的广度

我说一下我对程序应用的一个看法就是 我其实个人不太建议自动驾驶技术的发展因为这个东西它说到底还是什么那么一点安全隐患 ,虽然我们平常考虑用同时实行各种各样的高级的自动作用, 但是自动驾驶可能是个特例,其实我个人觉得程序可以在以下方面发展 1.医学(包括诊断 治疗 手术等)因为现在也有很多的疾病是医学还没有能力去解决的 ,2.国防 有的时候因为国家安全真的非常重要的,因为我们每个人

堆-数组的堆化+优先队列(PriorityQueue)的使用

一、堆 1、什么是堆? 以完全二叉树的形式将元素存储到对应的数组位置上所形成的新数组 2、为什么要将数组变成堆? 当数组中的元素连续多次进行排序时会消耗大量的时间,将数组变成堆后通过堆排序的方式将会消耗更少的时间 二、接口 给堆定义一个接口,用来规范堆里面的方法 1、在获取堆顶元素和删除堆顶元素的方法中,都必须返回堆顶元素,当堆为空时,返回异常对象要比返回null关键字更加安全 定