数据结构第14节 加权图

加权图是在图论中一种更为复杂的图结构,它扩展了无向图和有向图的概念,通过给图中的边附加一个数值来表示边的某种属性,如成本、距离、容量或相似度等。这个数值被称为边的“权重”。

定义

加权图可以被形式化地定义为一个三元组 ( G = (V, E, W) ),其中:

  • ( V ) 是顶点的集合。
  • ( E ) 是边的集合,每条边连接 ( V ) 中的一对顶点。
  • ( W ) 是一个函数,将每条边映射到一个实数上,即 ( W: E \rightarrow \mathbb{R} )。

分类

加权图可以根据边的方向进一步分类为:

  • 加权无向图:图中的边没有方向,权重是对称的,即 ( W(u,v) = W(v,u) )。
  • 加权有向图:图中的边有方向,权重可能不对称,即 ( W(u,v) ) 可能与 ( W(v,u) ) 不同。

权重的意义

在不同的应用场景中,权重可以有不同的含义:

  • 在网络路由中,权重可能是网络链路的延迟或带宽。
  • 在交通网络中,权重可能是道路的距离或通行时间。
  • 在电子电路中,权重可能是电阻或电容值。
  • 在社交网络中,权重可以表示人际关系的强度。

图的表示

加权图可以通过以下几种方式表示:

  • 邻接矩阵:对于加权图,邻接矩阵中的非零元素表示边的权重。
  • 邻接列表:对于每个顶点,列表中的每个元素除了包含邻接顶点的信息外,还包含边的权重。

常见算法

处理加权图的一些常见算法包括:

  • 最短路径算法:如Dijkstra算法和Bellman-Ford算法,用于找到两点间具有最小权重和的路径。
  • 最小生成树算法:如Prim算法和Kruskal算法,用于在加权连通图中找到一棵包含所有顶点的最小权重的树。
  • 最大流算法:如Ford-Fulkerson算法,用于在有向加权图中找到从源点到汇点的最大流。
  • 匹配算法:如匈牙利算法,用于在加权二部图中找到最优匹配。

实际应用

加权图在多个领域有着广泛的应用,包括:

  • 物流和运输系统:规划最短路线或最低成本的配送路径。
  • 网络通信:优化数据包的传输路径,以减少延迟或提高效率。
  • 生物信息学:构建基因或蛋白质网络,分析其相互作用。
  • 机器学习:构建基于图的模型,如图神经网络,用于预测和分类任务。

加权图是理解和建模现实世界中复杂关系的重要工具,其研究不仅限于理论数学,也与计算机科学、工程学、经济学和生物学等领域密切相关。

为了更深入理解加权图,我们可以考虑一个具体案例:在一个城市交通网络中寻找两点之间的最短路径。在这个网络中,边的权重代表两个地点之间的行驶时间(或者距离)。我们将使用Dijkstra算法来解决这个问题,该算法是一种用于查找加权图中单源最短路径的经典算法。

背景

假设我们有一个城市,其中有若干个地点和连接它们的道路。每个地点都是图中的一个顶点,而每条道路则是一条有向或无向的边,且每条边都有一个权重,代表驾驶所需的时间。我们的目标是从某个起点出发,找到到达另一个终点的最短路径。

Java源代码实现

首先,我们需要定义加权图的数据结构,然后实现Dijkstra算法。以下是一个简化版的实现:

import java.util.*;class Edge {int dest;int weight;public Edge(int d, int w) {dest = d;weight = w;}
}class Node {List<Edge> neighbors = new ArrayList<>();boolean visited = false;int distance = Integer.MAX_VALUE;Node previous = null;
}public class DijkstraAlgorithm {private List<Node> nodes = new ArrayList<>();public void addNode() {nodes.add(new Node());}public void addEdge(int source, int destination, int weight) {Node srcNode = nodes.get(source);Node destNode = nodes.get(destination);srcNode.neighbors.add(new Edge(destNode, weight));}public void dijkstra(int startNode) {PriorityQueue<Node> queue = new PriorityQueue<>(Comparator.comparingInt(node -> node.distance));Node start = nodes.get(startNode);start.distance = 0;queue.add(start);while (!queue.isEmpty()) {Node current = queue.poll();if (current.visited)continue;for (Edge edge : current.neighbors) {Node neighbor = edge.dest;int tentativeDistance = current.distance + edge.weight;if (tentativeDistance < neighbor.distance) {neighbor.distance = tentativeDistance;neighbor.previous = current;queue.add(neighbor);}}current.visited = true;}}public List<Integer> getPath(int destination) {List<Integer> path = new ArrayList<>();Node current = nodes.get(destination);while (current != null) {path.add(current.hashCode());current = current.previous;}Collections.reverse(path);return path;}public static void main(String[] args) {DijkstraAlgorithm graph = new DijkstraAlgorithm();// 添加节点for (int i = 0; i < 6; i++)graph.addNode();// 添加边graph.addEdge(0, 1, 5);graph.addEdge(0, 2, 3);graph.addEdge(1, 3, 6);graph.addEdge(1, 2, 2);graph.addEdge(2, 4, 4);graph.addEdge(2, 5, 2);graph.addEdge(3, 4, -2); // 负权重边,但Dijkstra不处理负权重环graph.addEdge(4, 5, 1);// 执行Dijkstra算法graph.dijkstra(0);// 输出最短路径System.out.println("Shortest Path to all nodes from node 0:");for (int i = 0; i < graph.nodes.size(); i++) {System.out.println("To node " + i + ": " + graph.getPath(i));}}
}

解析

  1. Edge 类定义了边的目的地和权重。
  2. Node 类定义了顶点的邻居列表、是否访问过、当前距离和前驱节点。
  3. DijkstraAlgorithm 类实现了加权图的添加节点和边的功能,以及Dijkstra算法的执行。
  4. 主方法中创建图、添加节点和边,执行Dijkstra算法并打印出从起始点到所有其他点的最短路径。

这个Demo展示了如何使用Java实现加权图以及Dijkstra算法的基本框架,实际应用中可能需要根据具体需求进行调整和优化。例如,处理大规模图时,可能需要更高效的数据结构和算法优化,如使用Fibonacci堆代替优先队列。

Demo展示

1. 迷宫游戏:寻找出口

在迷宫游戏中,玩家需要从起点出发,找到通往终点的路径。这可以通过图论中的搜索算法来实现,例如深度优先搜索(DFS)或广度优先搜索(BFS)。

Java代码示例:使用DFS寻找迷宫出口
import java.util.*;public class MazeGame {private static final int[][] DIRECTIONS = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};private char[][] maze;private boolean[][] visited;public MazeGame(char[][] maze) {this.maze = maze;this.visited = new boolean[maze.length][maze[0].length];}private boolean dfs(int x, int y) {if (x < 0 || x >= maze.length || y < 0 || y >= maze[0].length || maze[x][y] == '#' || visited[x][y]) {return false;}if (maze[x][y] == 'E') {return true;}visited[x][y] = true;for (int[] dir : DIRECTIONS) {if (dfs(x + dir[0], y + dir[1])) {return true;}}return false;}public boolean hasPath() {for (int i = 0; i < maze.length; i++) {for (int j = 0; j < maze[0].length; j++) {if (maze[i][j] == 'S') {return dfs(i, j);}}}return false;}public static void main(String[] args) {char[][] maze = {{'#', '#', '#', '#', 'S', '#', '#'},{'#', '.', '.', '.', '.', '.', '#'},{'#', '#', '#', '#', '#', '.', '#'},{'#', '.', '.', '.', '.', '.', '#'},{'#', '#', '#', '#', '#', 'E', '#'}};MazeGame game = new MazeGame(maze);System.out.println(game.hasPath() ? "There is a path." : "There is no path.");}
}

2. 策略游戏:资源收集与管理

在策略游戏中,玩家需要收集资源、建设设施,并管理资源分配。这可以通过构建加权图,其中节点代表资源点或设施,边的权重代表资源的流动成本或收益。

Java代码示例:资源管理加权图
import java.util.*;public class ResourceManagementGame {private Map<String, List<Pair<String, Integer>>> graph = new HashMap<>();public void addNode(String name) {graph.putIfAbsent(name, new ArrayList<>());}public void addEdge(String source, String target, int weight) {graph.get(source).add(new Pair<>(target, weight));}public int calculateTotalResources(String start, int resources) {Set<String> visited = new HashSet<>();Queue<Pair<String, Integer>> queue = new LinkedList<>();queue.add(new Pair<>(start, resources));while (!queue.isEmpty()) {Pair<String, Integer> current = queue.poll();String node = current.getKey();int resource = current.getValue();if (visited.contains(node)) continue;visited.add(node);resource += processNode(node);for (Pair<String, Integer> next : graph.get(node)) {queue.add(new Pair<>(next.getKey(), resource - next.getValue()));}}return resources;}private int processNode(String node) {// Simulate resource processing at each nodereturn node.equals("mine") ? 10 : 0;}public static void main(String[] args) {ResourceManagementGame game = new ResourceManagementGame();game.addNode("mine");game.addNode("factory");game.addNode("warehouse");game.addEdge("mine", "factory", 2);game.addEdge("factory", "warehouse", 3);game.addEdge("warehouse", "mine", 1);System.out.println("Total resources: " + game.calculateTotalResources("mine", 100));}
}class Pair<K, V> {private K key;private V value;public Pair(K key, V value) {this.key = key;this.value = value;}public K getKey() {return key;}public V getValue() {return value;}
}

3. 棋盘游戏:策略与移动

在棋盘游戏中,玩家需要在棋盘上移动棋子以达成胜利条件。棋盘上的每个位置可以视为图中的一个节点,而合法的移动则构成边。

Java代码示例:国际象棋中的骑士走法
import java.util.*;public class ChessKnightMoves {private static final int[][] MOVES = {{2, 1}, {1, 2}, {-1, 2}, {-2, 1}, {-2, -1}, {-1, -2}, {1, -2}, {2, -1}};public int minMoves(int startX, int startY, int endX, int endY) {int[][] board = new int[8][8];Queue<int[]> queue = new LinkedList<>();queue.add(new int[]{startX, startY});board[startX][startY] = 1;while (!queue.isEmpty()) {int[] pos = queue.poll();if (pos[0] == endX && pos[1] == endY) {return board[pos[0]][pos[1]] - 1;}for (int[] move : MOVES) {int newX = pos[0] + move[0];int newY = pos[1] + move[1];if (newX >= 0 && newX < 8 && newY >= 0 && newY < 8 && board[newX][newY] == 0) {queue.add(new int[]{newX, newY});board[newX][newY] = board[pos[0]][pos[1]] + 1;}}}return -1;}public static void main(String[] args) {ChessKnightMoves game = new ChessKnightMoves();System.out.println("Minimum moves: " + game.minMoves(0, 0, 7, 7));}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/42063.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vortex GPGPU的硬件设计和代码结构分析

文章目录 前言一、GPGPU是什么&#xff1f;1.1 GPU和GPGPU之间的差异1.2 GPU和CPU之间的集成方式1.3 GPU包含什么&#xff08;列举和VMIPS向量体系结构的差异&#xff09; 二、Vortex GPGPU是什么&#xff1f;2.1 Vortex GPGPU的技术边界和验证环境2.2 Vortex GPGPU的指令集设计…

安卓稳定性之crash详解

目录 前言一、Crash 的基本原理二、Crash 分析思路三、实例分析四、预防措施五、参考链接 前言 在开发和测试 Android 应用程序时&#xff0c;遇到应用程序崩溃是很常见的情况。 Android 崩溃指的是应用程序因为异常或错误而无法正常执行&#xff0c;并且导致应用强制关闭。 一…

p11函数和递归

递归与迭代 求n的阶乘。&#xff08;不考虑溢出&#xff09; int Fac1(int n) {int i0;int ret1;for(i1;i<n;i){ret*i;}return ret; } int main(){//求n的阶乘int n0;int ret0;scanf("%d",&n);retFac1(n);printf("%d\n",ret);return 0; } int Fac…

什么是激光导航和视觉导航技术

激光导航和视觉导航技术是现代导航系统中的两种重要技术&#xff0c;它们在多个领域&#xff0c;如扫地机器人、无人机、机器人导航等中都有广泛应用。以下是对这两种技术的详细介绍&#xff1a; 一、激光导航技术 1. 定义与原理 激光导航技术是一种利用激光束进行精确测量和…

ChatGPT:||是短路运算符,那么|、、是什么?

ChatGPT&#xff1a;||是短路运算符&#xff0c;那么|、&、&&是什么? 在Java中&#xff0c;逻辑运算符&&和||是短路逻辑运算符&#xff0c;而&和|是非短路逻辑运算符。 && 和 || 是短路逻辑运算符。当使用这些运算符时&#xff0c;如果第一个…

解决 Docker 容器镜像拉取难题:全面指南

一、引言 在使用 Docker 容器的过程中&#xff0c;经常会遇到镜像拉取慢甚至无法下载的问题&#xff0c;这给开发和部署工作带来了不小的困扰。本文将深入探讨这一问题的原因&#xff0c;并提供多种有效的解决方案。 二、问题原因分析 网络限制 本地网络带宽不足或存在网络拥…

unity知识点 专项四 一文彻底说清楚(锚点(anchor)、中心点(pivot)、位置(position)之间的关系)

一 概述 想要使UI控件在屏幕中达到正确的显示效果&#xff0c;比如自适应屏幕尺寸、固定边距等等&#xff0c;首先要理清楚几个基本概念和设置&#xff1a;锚点(anchor)、中心点(pivot)、位置(position)、UI缩放模式、父物件的transform设置 二 Anchor、Pivot与Position 2…

网络连接线相关问题

问题1&#xff1b; 直通线为什么两头都是T568B&#xff1f;是否可以两台T5568A&#xff1f;或者任意线序&#xff0c;只需两头一致&#xff1f; 不行&#xff0c;施工规范规定。&#xff08;原因&#xff1b;网线最长距离100m&#xff0c;实际用起来要把网线包管&#xff0c;走…

【分布式系统】Filebeat+Kafka+ELK 的服务部署

目录 一.实验准备 二.配置部署 Filebeat 三.配置Logstash 四.验证 一.实验准备 结合之前的博客中的实验 主机名ip地址主要软件es01192.168.80.101ElasticSearches02192.168.80.102ElasticSearches03192.168.80.103ElasticSearch、Kibananginx01192.168.80.104nginx、Logs…

iperf3: error - unable to connect to server: No route to host

1.确认iperf3版本是否统一。 2.确认防火墙是否关闭。 关闭防火墙 : systemctl stop firewalld 查看防火墙状态: systemctl status firewalld 3.重新建起链接

Java进阶----接口interface

接口 接口概述 接口是一种规范&#xff0c;使用接口就代表着要在程序中制定规范. 制定规范可以给不同类型的事物定义功能&#xff0c;例如&#xff1a; 利用接口&#xff0c;给飞机、小鸟制定飞行规范&#xff0c;让其都具备飞行的功能&#xff1b;利用接口&#xff0c;给鼠…

SMU Summer 2024 Contest Round 1

A.Hcode OnlineJudge 给出一个N面骰子和整数K&#xff0c;掷出1-N之间的每个数的概率相同&#xff0c;每次掷出一次&#xff0c;记为成绩&#xff0c;若成绩小于K&#xff0c;则开始抛硬币&#xff0c;硬币朝上则数翻倍&#xff0c;反之则为0&#xff0c;概率都为0.5。当数大于…

自动驾驶算法———车道检测(一)

“ 在本章中&#xff0c;我将指导您构建一个简单但有效的车道检测管道&#xff0c;并将其应用于Carla 模拟器中捕获的图像。管道将图像作为输入&#xff0c;并产生车道边界的数学模型作为输出。图像由行车记录仪&#xff08;固定在车辆挡风玻璃后面的摄像头&#xff09;捕获。…

【ZIP压缩大揭秘】轻松掌握ZIP分卷压缩包的高效解压秘籍!

在这个信息爆炸的时代&#xff0c;文件大小常常成为我们分享与存储的绊脚石。幸运的是&#xff0c;ZIP分卷压缩技术如同一把钥匙&#xff0c;巧妙地将庞然大物分解成小巧易管理的部分。但面对这一串分卷压缩包&#xff0c;你是否也曾迷茫于如何高效解压&#xff0c;恢复文件的完…

解码Python字符串:‘r‘、‘b‘、‘u‘和‘f‘前缀的全面指南

&#x1f4d6; 正文 1 字符串前加’r’ 表示原始字符串&#xff0c;消除转义 print(abc\nde) # abc # deprint(rabc\nde) # abc\nde在下面这个列子中&#xff0c;如果不在路径字符串前面加r那么&#xff0c;路径中的空格就会出现问题 print(rD:\01 programming\09python\py…

全志A527 T527 cat /proc/cupinfo没有Serial问题

1.前言 我们有些客户是使用cpuinfo节点去获取系统的cpuid的,如下: cat /proc/cupinfo processor : 0 BogoMIPS : 48.00 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp CPU impleme…

系统吃swap问题排查

目录 背景 问题 分析并解决 1.控制线程数 2.更换IO组件 3.Linux进程信息文件分析 总结加餐 参考文档 背景 隔壁业务组系统是简单的主从结构&#xff0c;写索引的服务(主)叫primary&#xff0c; 读索引并提供搜索功能的服务(从)叫replica。业务线同步数据并不是平滑的&…

离散化及其在 Pandas 中的实现方法

目录 1.什么是离散化&#xff1f; 2.离散化类型 3.示例代码 3.1连续变量离散化 3.2定性变量离散化 4.运行结果 4.1连续变量离散化 4.2定性变量离散化 1.什么是离散化&#xff1f; 离散化是将连续数据或分类数据转换为离散类别的过程&#xff0c;方便后续的数据分析和机…

static的理论学习

在说到static之前&#xff0c;需要先明确变量类型&#xff1a; 而在聊到变量类型之前我们可以将变量的两个属性好好学一学 变量的两个属性 作用域&#xff08;scope&#xff09;&#xff1a; 从内存的角度来看&#xff0c;就是变量存放在栈&#xff08;stack&#xff09;中&…

在 JavaScript 中,??(双问号运算符)和 ?.(可选链运算符)区别

在 JavaScript 中&#xff0c;??&#xff08;双问号运算符&#xff09;和 ?.&#xff08;可选链运算符&#xff09;是两种不同的运算符&#xff0c;用于处理不同的情况&#xff1a; 双问号运算符 (??): ?? 运算符是空值合并运算符&#xff08;Nullish Coalescing Oper…