贪心算法应用:顶点覆盖问题详解

在这里插入图片描述

贪心算法应用:顶点覆盖问题详解

贪心算法是解决顶点覆盖问题的经典方法之一。下面我将从基础概念到高级优化,全面详细地讲解顶点覆盖问题及其贪心算法解决方案。

一、顶点覆盖问题基础

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.mzph.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 比较…