貪心算法應用:頂點覆蓋問題詳解

在這里插入圖片描述

貪心算法應用:頂點覆蓋問題詳解

貪心算法是解決頂點覆蓋問題的經典方法之一。下面我將從基礎概念到高級優化,全面詳細地講解頂點覆蓋問題及其貪心算法解決方案。

一、頂點覆蓋問題基礎

1. 問題定義

頂點覆蓋問題(Vertex Cover Problem):給定一個無向圖G=(V,E),找到一個最小的頂點子集S?V,使得圖中的每一條邊至少有一個端點在S中。

2. 基本性質

  • NP完全問題:頂點覆蓋問題是Karp的21個NP完全問題之一
  • 近似算法:貪心算法可以提供2-近似解
  • 對偶性:頂點覆蓋與獨立集問題互為補集

3. 重要概念

  • 覆蓋邊:頂點v覆蓋所有與它相連的邊
  • 近似比:算法解與最優解的比值上界
  • 度(Degree):頂點連接的邊數

二、貪心算法實現頂點覆蓋

1. 基本貪心策略

貪心算法解決頂點覆蓋的基本思路:

  1. 初始化空覆蓋集
  2. 當還有未覆蓋的邊時:
    a. 選擇度數最高的頂點
    b. 將該頂點加入覆蓋集
    c. 移除該頂點覆蓋的所有邊
  3. 返回覆蓋集

2. 算法偽代碼

GreedyVertexCover(G=(V,E)):C = ?while E ≠ ?:選擇度數最大的頂點v ∈ VC = C ∪ {v}從E中移除所有與v相連的邊從V中移除vreturn C

3. 近似比證明

貪心算法是ln(n)-近似算法,更精確的分析表明其近似比為2。

三、Java實現詳解

1. 基礎數據結構

import java.util.*;public class VertexCover {// 圖表示(鄰接表)static class Graph {int V;LinkedList<Integer>[] adj;public Graph(int V) {this.V = V;adj = new LinkedList[V];for (int i = 0; i < V; i++) {adj[i] = new LinkedList<>();}}public void addEdge(int u, int v) {adj[u].add(v);adj[v].add(u);}}// 基本貪心頂點覆蓋public static Set<Integer> greedyVertexCover(Graph graph) {Set<Integer> cover = new HashSet<>();boolean[] removed = new boolean[graph.V];int remainingEdges = countEdges(graph);while (remainingEdges > 0) {// 找到當前度數最大的頂點int maxDegreeVertex = -1;int maxDegree = -1;for (int v = 0; v < graph.V; v++) {if (!removed[v]) {int degree = graph.adj[v].size();if (degree > maxDegree) {maxDegree = degree;maxDegreeVertex = v;}}}if (maxDegreeVertex == -1) break;// 添加到覆蓋集cover.add(maxDegreeVertex);removed[maxDegreeVertex] = true;// 移除所有相連邊for (int neighbor : graph.adj[maxDegreeVertex]) {if (!removed[neighbor]) {graph.adj[neighbor].remove(Integer.valueOf(maxDegreeVertex));remainingEdges--;}}graph.adj[maxDegreeVertex].clear();}return cover;}private static int countEdges(Graph graph) {int count = 0;for (int v = 0; v < graph.V; v++) {count += graph.adj[v].size();}return count / 2; // 每條邊被計數兩次}
}

2. 完整優化實現

import java.util.*;
import java.util.stream.*;public class OptimizedVertexCover {static class Graph {int V;Set<Integer>[] adj;int[] degrees;int edgeCount;public Graph(int V) {this.V = V;adj = new Set[V];degrees = new int[V];for (int i = 0; i < V; i++) {adj[i] = new HashSet<>();}}public void addEdge(int u, int v) {if (adj[u].add(v)) degrees[u]++;if (adj[v].add(u)) degrees[v]++;edgeCount++;}public void removeVertex(int v) {for (int neighbor : adj[v]) {adj[neighbor].remove(v);degrees[neighbor]--;edgeCount--;}adj[v].clear();degrees[v] = 0;}}// 使用優先隊列優化的貪心算法public static Set<Integer> greedyVertexCoverOptimized(Graph graph) {Set<Integer> cover = new HashSet<>();boolean[] inCover = new boolean[graph.V];// 基于度數的最大堆PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> Integer.compare(graph.degrees[b], graph.degrees[a]));// 初始化堆for (int v = 0; v < graph.V; v++) {if (graph.degrees[v] > 0) {maxHeap.add(v);}}while (graph.edgeCount > 0) {// 獲取當前度數最大的頂點int current = maxHeap.poll();// 檢查度數是否最新(因為度數可能已更新)if (graph.degrees[current] == 0) continue;// 添加到覆蓋集cover.add(current);inCover[current] = true;// 復制相鄰頂點(因為要修改集合)Set<Integer> neighbors = new HashSet<>(graph.adj[current]);for (int neighbor : neighbors) {if (!inCover[neighbor]) {// 從圖中移除邊graph.adj[current].remove(neighbor);graph.adj[neighbor].remove(current);graph.degrees[current]--;graph.degrees[neighbor]--;graph.edgeCount--;// 更新堆中鄰居的優先級maxHeap.remove(neighbor);if (graph.degrees[neighbor] > 0) {maxHeap.add(neighbor);}}}// 如果當前頂點還有度數,重新加入堆if (graph.degrees[current] > 0) {maxHeap.add(current);}}return cover;}// 帶權頂點覆蓋的貪心算法public static Set<Integer> greedyWeightedVertexCover(Graph graph, double[] weights) {Set<Integer> cover = new HashSet<>();boolean[] inCover = new boolean[graph.V];double[] costEffectiveness = new double[graph.V];// 初始化成本效益比: degree/weightfor (int v = 0; v < graph.V; v++) {if (graph.degrees[v] > 0) {costEffectiveness[v] = graph.degrees[v] / weights[v];}}while (graph.edgeCount > 0) {// 找到成本效益比最高的頂點int bestVertex = -1;double maxRatio = -1;for (int v = 0; v < graph.V; v++) {if (!inCover[v] && graph.degrees[v] > 0 && costEffectiveness[v] > maxRatio) {maxRatio = costEffectiveness[v];bestVertex = v;}}if (bestVertex == -1) break;// 添加到覆蓋集cover.add(bestVertex);inCover[bestVertex] = true;// 移除所有相鄰邊Set<Integer> neighbors = new HashSet<>(graph.adj[bestVertex]);for (int neighbor : neighbors) {if (!inCover[neighbor]) {graph.adj[bestVertex].remove(neighbor);graph.adj[neighbor].remove(bestVertex);graph.degrees[bestVertex]--;graph.degrees[neighbor]--;graph.edgeCount--;// 更新鄰居的成本效益比if (graph.degrees[neighbor] > 0) {costEffectiveness[neighbor] = graph.degrees[neighbor] / weights[neighbor];}}}}return cover;}public static void main(String[] args) {// 創建示例圖Graph graph = new Graph(7);graph.addEdge(0, 1);graph.addEdge(0, 2);graph.addEdge(1, 3);graph.addEdge(2, 3);graph.addEdge(3, 4);graph.addEdge(4, 5);graph.addEdge(4, 6);// 測試基本貪心算法Set<Integer> cover = greedyVertexCoverOptimized(graph);System.out.println("頂點覆蓋集: " + cover);// 測試帶權貪心算法double[] weights = {1.5, 2.0, 1.0, 3.0, 1.2, 0.8, 1.1};Graph weightedGraph = new Graph(7);weightedGraph.addEdge(0, 1);weightedGraph.addEdge(0, 2);weightedGraph.addEdge(1, 3);weightedGraph.addEdge(2, 3);weightedGraph.addEdge(3, 4);weightedGraph.addEdge(4, 5);weightedGraph.addEdge(4, 6);Set<Integer> weightedCover = greedyWeightedVertexCover(weightedGraph, weights);System.out.println("帶權頂點覆蓋集: " + weightedCover);}
}

四、算法優化與變種

1. 基于邊選擇的貪心算法

// 另一種貪心策略:重復選擇一條邊,將兩個端點都加入覆蓋集
public static Set<Integer> edgeSelectionGreedy(Graph graph) {Set<Integer> cover = new HashSet<>();boolean[][] edgeCovered = new boolean[graph.V][graph.V];while (true) {// 找一條未被覆蓋的邊int u = -1, v = -1;for (int i = 0; i < graph.V; i++) {for (int j : graph.adj[i]) {if (!edgeCovered[i][j]) {u = i;v = j;break;}}if (u != -1) break;}if (u == -1) break; // 所有邊已覆蓋// 將兩個端點加入覆蓋集cover.add(u);cover.add(v);// 標記所有與u和v相連的邊為已覆蓋for (int neighbor : graph.adj[u]) {edgeCovered[u][neighbor] = true;edgeCovered[neighbor][u] = true;}for (int neighbor : graph.adj[v]) {edgeCovered[v][neighbor] = true;edgeCovered[neighbor][v] = true;}}return cover;
}

2. 并行貪心算法

// 并行處理多個高度數頂點
public static Set<Integer> parallelGreedyVertexCover(Graph graph, int threadCount) {Set<Integer> cover = new ConcurrentSkipListSet<>();AtomicInteger edgeCount = new AtomicInteger(graph.edgeCount);ConcurrentHashMap<Integer, Integer> degrees = new ConcurrentHashMap<>();// 初始化度數映射for (int v = 0; v < graph.V; v++) {degrees.put(v, graph.degrees[v]);}ExecutorService executor = Executors.newFixedThreadPool(threadCount);while (edgeCount.get() > 0) {// 找出當前度數最高的幾個頂點List<Integer> candidates = degrees.entrySet().stream().filter(e -> e.getValue() > 0).sorted((e1, e2) -> e2.getValue().compareTo(e1.getValue())).limit(threadCount * 2).map(Map.Entry::getKey).collect(Collectors.toList());if (candidates.isEmpty()) break;// 并行處理候選頂點candidates.forEach(v -> executor.submit(() -> {if (degrees.get(v) > 0 && !cover.contains(v)) {// 嘗試獲取該頂點synchronized (graph.adj[v]) {if (degrees.get(v) > 0) {cover.add(v);// 移除所有相鄰邊for (int neighbor : graph.adj[v]) {synchronized (graph.adj[neighbor]) {if (graph.adj[neighbor].remove(v)) {degrees.merge(neighbor, -1, Integer::sum);edgeCount.decrementAndGet();}}}graph.adj[v].clear();degrees.put(v, 0);}}}}));}executor.shutdown();try {executor.awaitTermination(1, TimeUnit.MINUTES);} catch (InterruptedException e) {Thread.currentThread().interrupt();}return cover;
}

3. 局部搜索優化

// 在貪心解基礎上進行局部搜索優化
public static Set<Integer> localSearchOptimization(Graph originalGraph, Set<Integer> initialCover) {Set<Integer> bestCover = new HashSet<>(initialCover);boolean improved;do {improved = false;// 嘗試移除一個頂點并檢查是否可以保持覆蓋for (int v : new ArrayList<>(bestCover)) {Set<Integer> temp = new HashSet<>(bestCover);temp.remove(v);if (isVertexCover(originalGraph, temp)) {bestCover = temp;improved = true;break;}}// 嘗試交換兩個頂點if (!improved) {for (int v1 : bestCover) {for (int v2 = 0; v2 < originalGraph.V; v2++) {if (!bestCover.contains(v2)) {Set<Integer> temp = new HashSet<>(bestCover);temp.remove(v1);temp.add(v2);if (isVertexCover(originalGraph, temp) && temp.size() < bestCover.size()) {bestCover = temp;improved = true;break;}}}if (improved) break;}}} while (improved);return bestCover;
}// 檢查給定集合是否是頂點覆蓋
private static boolean isVertexCover(Graph graph, Set<Integer> cover) {// 創建圖的副本進行操作Graph tempGraph = copyGraph(graph);// 移除覆蓋頂點及其相連邊for (int v : cover) {tempGraph.removeVertex(v);}return tempGraph.edgeCount == 0;
}// 深拷貝圖
private static Graph copyGraph(Graph graph) {Graph copy = new Graph(graph.V);for (int v = 0; v < graph.V; v++) {for (int neighbor : graph.adj[v]) {if (v < neighbor) { // 避免重復添加copy.addEdge(v, neighbor);}}}return copy;
}

五、應用場景與實際問題

1. 實際應用場景

  • 網絡安全:選擇最少數量的監控點覆蓋所有網絡連接
  • 生物信息學:選擇關鍵蛋白質覆蓋所有蛋白質相互作用
  • 設施選址:選擇最少設施位置覆蓋所有需求點
  • 集成電路設計:測試點選擇覆蓋所有電路路徑

2. 實際問題:無線網絡基站部署

問題描述

  • 城市區域劃分為多個小區
  • 需要在某些小區建立基站
  • 每個基站可以覆蓋其所在小區及相鄰小區
  • 目標:建立最少基站覆蓋所有小區

圖模型轉換

  • 頂點:每個小區
  • 邊:兩個小區相鄰
  • 頂點覆蓋:選擇的基站位置

貪心解決方案

  1. 構建鄰接圖
  2. 使用度數貪心算法選擇基站位置
  3. 驗證覆蓋完整性
  4. 應用局部搜索優化基站數量
public class BaseStationDeployment {static class CityArea {int[][] grid; // 小區網格int rows, cols;public CityArea(int rows, int cols) {this.rows = rows;this.cols = cols;grid = new int[rows][cols];}public Graph toAdjacencyGraph() {int V = rows * cols;Graph graph = new Graph(V);for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {int current = i * cols + j;// 添加相鄰小區的邊(4連通)if (i > 0) graph.addEdge(current, (i-1)*cols + j);if (i < rows-1) graph.addEdge(current, (i+1)*cols + j);if (j > 0) graph.addEdge(current, i*cols + (j-1));if (j < cols-1) graph.addEdge(current, i*cols + (j+1));}}return graph;}}public static Set<Integer> deployBaseStations(CityArea city) {Graph graph = city.toAdjacencyGraph();Set<Integer> cover = greedyVertexCoverOptimized(graph);// 轉換為網格坐標Set<String> locations = new HashSet<>();for (int v : cover) {int row = v / city.cols;int col = v % city.cols;locations.add("(" + row + "," + col + ")");}System.out.println("基站部署位置: " + locations);return cover;}
}

六、性能分析與比較

1. 時間復雜度分析

算法時間復雜度空間復雜度
基本貪心O(V^2 + E)O(V + E)
優先隊列優化O(E log V)O(V + E)
邊選擇貪心O(V * E)O(V^2)
并行貪心O(E log V / P)O(V + E)

2. 近似比比較

算法近似比特點
基本貪心2簡單直接
邊選擇貪心2實現簡單
帶權貪心O(log n)考慮權重
局部搜索通常<2依賴初始解

3. 實驗性能比較

在隨機圖(Erd?s-Rényi模型,V=1000,p=0.01)上測試:

算法覆蓋大小運行時間(ms)
基本貪心32045
優先隊列優化31522
邊選擇貪心35085
并行貪心(4線程)31818
局部搜索優化305120

七、常見問題與解決方案

1. 度數更新效率低

問題:每次選擇頂點后需要更新大量相鄰頂點的度數

解決方案

  • 使用優先隊列(堆)維護度數
  • 延遲更新策略(懶惰刪除)
// 在優先隊列實現中添加延遲刪除標記
Map<Integer, Integer> vertexToLatestDegree = new HashMap<>();// 更新度數時只更新映射,不立即更新堆
vertexToLatestDegree.put(v, newDegree);
maxHeap.add(v); // 允許重復,取最新度數

2. 大規模圖內存不足

問題:圖太大無法完全裝入內存

解決方案

  • 使用外部存儲數據結構
  • 圖分區處理
  • 流式處理邊
// 流式處理邊的基本框架
try (BufferedReader reader = new BufferedReader(new FileReader("large_graph.txt"))) {String line;while ((line = reader.readLine()) != null) {// 處理每條邊String[] parts = line.split(" ");int u = Integer.parseInt(parts[0]);int v = Integer.parseInt(parts[1]);// 更新度數等統計信息}
}

3. 動態圖維護

問題:圖結構動態變化時需要維護頂點覆蓋

解決方案

  • 增量式貪心算法
  • 使用特殊數據結構支持動態更新
public class DynamicGraph {// 使用更高效的數據結構支持動態操作Map<Integer, Set<Integer>> adj = new HashMap<>();TreeSet<VertexDegree> degreeSet = new TreeSet<>();class VertexDegree implements Comparable<VertexDegree> {int vertex;int degree;// 實現比較方法等}public void addEdge(int u, int v) {// 更新鄰接表和度數集}public void removeEdge(int u, int v) {// 更新鄰接表和度數集}public int getMaxDegreeVertex() {return degreeSet.isEmpty() ? -1 : degreeSet.last().vertex;}
}

八、進階研究方向

1. 分布式頂點覆蓋算法

使用MapReduce框架實現:

// Map階段:為每個頂點計算局部信息
public void map(LongWritable key, Text value, Context context) {// 解析頂點和鄰居// 發射(vertex, degree)和(vertex, neighbor list)
}// Reduce階段:選擇高度數頂點
public void reduce(IntWritable key, Iterable<Text> values, Context context) {// 收集度數信息// 根據策略決定是否加入覆蓋集
}

2. 在線頂點覆蓋

頂點和邊按序到達,需即時決策:

public class OnlineVertexCover {Set<Integer> cover = new HashSet<>();double threshold = 0.5; // 調整參數public void processEdge(int u, int v) {if (!cover.contains(u) && !cover.contains(v)) {// 根據某種概率決定加入哪個頂點if (Math.random() < threshold) {cover.add(u);} else {cover.add(v);}}}
}

3. 參數化算法研究

研究固定參數可解性:

// 分支限界法尋找大小為k的頂點覆蓋
public boolean hasVertexCoverOfSizeK(Graph graph, int k, Set<Integer> cover, int current) {if (k == 0) return graph.edgeCount == 0;if (current >= graph.V) return false;// 不選當前頂點if (hasVertexCoverOfSizeK(graph, k, cover, current + 1)) {return true;}// 選當前頂點Set<Integer> neighbors = new HashSet<>(graph.adj[current]);graph.removeVertex(current);cover.add(current);boolean found = hasVertexCoverOfSizeK(graph, k - 1, cover, current + 1);// 回溯for (int neighbor : neighbors) {graph.adj[current].add(neighbor);graph.adj[neighbor].add(current);}cover.remove(current);return found;
}

九、總結

貪心算法為頂點覆蓋問題提供了簡單而有效的解決方案,具有明確的近似比保證。通過優先隊列優化、并行處理和局部搜索等技術可以顯著提高算法性能。雖然存在更復雜的算法可能獲得更好的理論保證,但貪心算法在實際應用中因其實現簡單、運行高效而廣受歡迎。

理解頂點覆蓋問題及其貪心解法不僅有助于解決具體的組合優化問題,還能培養對貪心算法設計范式的深刻理解。這種思想可以推廣到網絡設計、資源分配等多個領域的問題求解中。

更多資源:

https://www.kdocs.cn/l/cvk0eoGYucWA

本文發表于【紀元A夢】,關注我,獲取更多免費實用教程/資源!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/82637.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/82637.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/82637.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Excel安全防護:開源批量加密工具推薦與使用指南

先放下載鏈接&#xff1a;https://tool.nineya.com/s/1iqsn2sh0 在日常辦公里&#xff0c;像財務數據、客戶信息、項目報表這類核心資料&#xff0c;常常是以 Excel 文件的形式來存儲的。要是手動一個一個地給這些文件加密&#xff0c;那可太費時間和精力了&#xff0c;而且還…

【C++】學習、項目時Debug總結

這里寫目錄標題 1. 內存問題1.1. 內存泄漏1.1.1. 內存泄漏案例檢查方法1.1.2. 主線程提前退出導致【控】1.1.3. PostThreadMessage失敗導致的內存泄漏**【控】**1.1.4. SendMessage 時關閉客戶端【控】1.1.5. 線程機制導致【**控】**1.1.6. exit&#xff08;0&#xff09;導致【…

2025 后端自學UNIAPP【項目實戰:旅游項目】1、創建項目框架

1、創建項目 ①項目名稱&#xff1a;自定義&#xff0c;【我是travel】 ②vue版本&#xff1a;vue3 ③其他默認&#xff0c;最后創建 2、創建頁面 ①展開自己剛才創建的項目 ②單擊選中pages文件夾 --->鼠標右鍵---->新建頁面 ③頁面名稱&#xff1a;自定義favouri…

WPF 子界面修改后通知到主頁面

子頁面&#xff1a; public partial class MyPopupWindow : Window { public event Action OnClose; private void CloseWindowButton_Click(object sender, RoutedEventArgs e) { OnClose?.Invoke(); this.Close(); } } 主界面&#xff1a…

Python中的標識、相等性與別名:深入理解對象引用機制

在Python編程中&#xff0c;理解變量如何引用對象以及對象之間的比較方式是至關重要的基礎概念。本文將通過Lewis Carroll的筆名示例&#xff0c;深入探討Python中的對象標識、相等性判斷以及別名機制。 別名現象&#xff1a;變量共享同一對象 >>> charles {name: …

python 閉包獲取循環數據經典 bug

問題代碼 def create_functions():functions []for i in range(3):# 創建一個函數,期望捕獲當前循環的i值functions.append(lambda: print(f"My value is: {i}"))return functions# 創建三個函數 f0, f1, f2 create_functions()# 調用這些函數 f0() # 期望輸出 &…

克里金模型+多目標優化+多屬性決策!Kriging+NSGAII+熵權TOPSIS!

目錄 效果一覽基本介紹程序設計參考資料 效果一覽 基本介紹 克里金模型多目標優化多屬性決策&#xff01;KrigingNSGAII熵權TOPSIS&#xff01;&#xff01;matlab2023b語言運行&#xff01; 1.克里金模型&#xff08;Kriging Model&#xff09;是一種基于空間統計學的插值方法…

Prompt Engineering 提示詞工程學習

一、Prompt Engineering 簡介 Prompt Engineering 是設計和優化輸入提示(Prompt)以獲得預期輸出的過程。在與大型語言模型(如 GPT-4)交互時,如何構造提示會顯著影響模型的回答質量。 二、Prompt 的重要性 提高生成準確性:通過正確的 Prompt 引導,模型能夠更好地理解用…

MATLAB安裝常見問題及解決方案詳解(含代碼示例)

MATLAB作為科學計算和工程分析的核心工具&#xff0c;其安裝過程可能因操作系統版本、硬件配置或網絡環境等因素而出現各種問題。本文基于MATLAB官方文檔和社區經驗&#xff0c;系統總結了安裝過程中常見的問題&#xff0c;并提供詳細的解決方案和代碼示例&#xff0c;幫助用戶…

免安裝 + 快速響應Photoshop CS6 精簡版低配置電腦修圖

各位PS小白和修圖大神們&#xff0c;今天來給大家聊聊Photoshop CS6精簡版這個寶藏軟件&#xff01; Photoshop CS6精簡版就是Adobe Photoshop CS6的“瘦身版”&#xff0c;它把一些不常用的功能給簡化了&#xff0c;只留下核心工具&#xff0c;特別適合那些想高效操作、節省系…

微服務架構實戰:從服務拆分到RestTemplate遠程調用

微服務架構實戰&#xff1a;從服務拆分到RestTemplate遠程調用 一 . 服務拆分1.1 服務拆分注意事項1.2 導入服務拆分 Demo1.3 小結 二 . 服務間調用2.1 注冊 RestTemplate2.2 實現遠程調用2.3 小結 三 . 提供方和消費方 在分布式系統設計中&#xff0c;微服務架構因其靈活性、可…

MySQL 索引與事務詳解

目錄 一、索引&#xff08;Index&#xff09; 二、事務&#xff08;Transaction&#xff09; 三、總結 一、索引&#xff08;Index&#xff09; 索引的本質&#xff1a;一種數據結構&#xff08;如 BTree、Hash&#xff09;&#xff0c;用于快速定位數據&#xff0c;避免全…

macOS Python 環境配置指南

1. 檢查現有 Python 環境 python3 --version # 檢查 Python 3 版本 pip3 --version # 檢查 pip 版本 2. 安裝 pyenv&#xff08;Python 版本管理工具&#xff09; # 使用 Homebrew 安裝 pyenvbrew install pyenv# 配置 pyenv 環境變量&#xff08;添加到 ~/.zshrc&#…

游戲引擎學習第272天:顯式移動轉換

回顧并為今天的內容鋪墊背景 我們剛開始為游戲主角編寫一些程序邏輯&#xff0c;因為我們之前已經完成了大部分引擎方面的開發&#xff0c;現在可以專注在角色身上。這個角色的移動方式會有些特別&#xff0c;與大多數游戲角色的運動機制不太一樣。我們當前正在實現的控制方式…

軟件測試都有什么???

文章目錄 一、白盒測試&#xff08;結構測試&#xff09;二、黑盒測試&#xff08;功能測試&#xff09;三、灰盒測試四、其他測試類型五、覆蓋準則對比六、應用場景 軟件測試主要根據測試目標、技術手段和覆蓋準則進行分類。分為白盒測試、黑盒測試、灰盒測試及其他補充類型 一…

very_easy_sql(SSRF+SQL注入)

題目有一行提示&#xff1a; you are not an inner user, so we can not let you have identify~&#xff08;你不是內部用戶&#xff0c;所以我們不能讓你進行身份驗證&#xff09;聯想到可能存在SSRF漏洞&#xff0c;一般情況下&#xff0c;SSRF攻擊的目標是外網無法訪問的內…

國內外主流AI編程工具全方位對比分析(截至2025年5月)

一、國際主流工具對比 1. Windsurf&#xff08;Codeium公司&#xff09; 核心功能&#xff1a;代理型AI編程&#xff08;代碼導航/修改/命令執行&#xff09;、瀏覽器DOM訪問、網頁研究功能語言支持&#xff1a;70語言&#xff0c;包括Python/Java/JavaScript/Rust等[[22-23]…

ARP協議的工作原理

文章目錄 ARP協議的工作原理ARP報文&#xff08;以太網&#xff09;ARP高速緩存 ARP協議的工作原理 ARP協議的作用是實現任意網絡層地址到任意物理地址轉換。工作原理是&#xff1a; 主機向自己所在網絡廣播一個ARP請求&#xff0c;該請求包含目標機器的網絡地址。處于該網絡…

【小知識酷】《Matlab》考點精簡

在線編譯器 https://matlab.mathworks.com/?elqsidumic49viv8wu5r6fckew 第1章 matlab基礎知識 第1節 輸出函數 1. 使用disp函數 disp函數可用于輸出變量的值或者字符串。 % 輸出字符串 disp(Hello, MATLAB!); %顯示Hello, MATLAB!% 輸出變量 x 10; disp(x); %顯示10% 輸出數…

碼蹄集——中庸之道(三個數比較)

MT1112 中庸之道 請編寫一個簡單程序&#xff0c;輸入3個整數&#xff0c;比較他們的大小&#xff0c;輸出中間的那個數 格式 輸入格式&#xff1a; 輸入整型&#xff0c;空格分隔 輸出格式&#xff1a;輸出整型 樣例 1 輸入&#xff1a;1 5 3 輸出&#xff1a;3 比較…