当前位置: 首页 > article >正文

【数据结构与算法】最小生成树Kruskal

1.#include iostream #include algorithm #include vector using namespace std; struct Edge { int u, v, w; // 起点终点边权 }; vectorEdge edges; vectorint parent; // 比较函数按边权升序排列 bool compareEdge(Edge a, Edge b) { return a.w b.w; // 小于号是升序大于号是降序 } // 并查集查找 int find(int x) { if (parent[x] ! x) parent[x] find(parent[x]); return parent[x]; } int main() { int N, M; cin N M; edges.resize(M); for (int i 0; i M; i) { cin edges[i].u edges[i].v edges[i].w; } // 使用比较函数排序 sort(edges.begin(), edges.end(), compareEdge); // 初始化并查集 parent.resize(N 1); for (int i 1; i N; i) { parent[i] i; } long long totalWeight 0; int edgesUsed 0; // Kruskal算法主循环 for (int i 0; i M; i) { int u edges[i].u; int v edges[i].v; int w edges[i].w; // 找到两个节点的根 int rootU find(u); int rootV find(v); // 如果不在同一集合加入生成树 if (rootU ! rootV) { parent[rootU] rootV; // 合并集合 totalWeight w; edgesUsed; // 已选够N-1条边结束 if (edgesUsed N - 1) { break; } } } // 输出结果 if (edgesUsed N - 1) { cout totalWeight endl; } else { cout orz endl; } return 0; }最小生成树Kruskal模板题详解并查集 贪心一次搞懂这道题是最标准的最小生成树模板题模型非常明确给你一个无向图选出若干条边把所有点连起来并且让总权值最小如果无法连通就输出 orz这种题基本可以一眼锁定 Kruskal 算法。Kruskal 的核心思想就是贪心按边权从小到大排序然后一条一条尝试加入如果这条边连接的两个点原本不连通就加入如果已经连通了再加就会形成环就跳过最终选出 n-1 条边就是最小生成树。先用结构体 Edge 存边再用 sort 按权值升序排序然后用并查集维护连通性parent 数组记录每个点的“祖先”find 函数带路径压缩可以加速查找在主循环中每次取一条边 (u, v, w)判断 find(u) 和 find(v) 是否相同如果不同就合并集合并把权值加入答案同时计数 edgesUsed。这里最关键的一步是“判环”并查集的作用就是判断两个点是否已经在同一个连通块中如果是就说明这条边会形成环必须跳过如果不是就说明这条边是“有用的”可以放心加入这也是 Kruskal 能保证正确性的核心。还有一个重要细节是终止条件当选的边数达到 N-1 时就可以提前结束因为最小生成树一定只有 N-1 条边最后再判断 edgesUsed 是否等于 N-1如果不是说明图不连通输出 orz。从直观上理解这个算法你可以想象在“修路”每次优先修最便宜的路但前提是这条路能连接两个原本不连通的区域最终用最少的钱把所有城市连起来这就是最小生成树的本质。总结一句Kruskal 边排序 并查集判环 贪心选边只要看到“无向图 连通所有点 权值最小”基本就是这一套模板熟练之后可以秒写。并查集朴素int parent[100]; // parent[i]表示i的父节点 // 初始化每个节点自成一家 void init(int n) { for (int i 1; i n; i) { parent[i] i; // 自己是自己的父亲 } } // 查找找根节点朋友圈老大 int find(int x) { while (parent[x] ! x) { x parent[x]; // 一直向上找 } return x; } // 合并把x和y所在集合合并 void unionSet(int x, int y) { int rootX find(x); int rootY find(y); if (rootX ! rootY) { parent[rootX] rootY; // 让一个根指向另一个根 } }路径压缩优化一个根下直接连接好多节点直接不压缩查找可能 O(n)压缩后查找接近 O(1)int find(int x) { if (parent[x] ! x) { parent[x] find(parent[x]); // 递归压缩 } return parent[x]; } // 或者非递归版本 int find(int x) { int root x; while (parent[root] ! root) { root parent[root]; // 先找到根 } // 路径压缩把路径上所有节点直接连到根 while (parent[x] ! root) { int temp parent[x]; parent[x] root; x temp; } return root; }int find(int x) { if (parent[x] ! x) { // 如果x不是根节点 parent[x] find(parent[x]); // 递归找根并压缩路径 } return parent[x]; // 返回根节点 }假设树结构1→2→3→44是根初始parent[1]2, parent[2]3, parent[3]4, parent[4]4 调用 find(1):find(1): parent[1]2≠1 → 进入if parent[1] find(parent[1]) find(2) // 先递归 find(2): parent[2]3≠2 → 进入if parent[2] find(parent[2]) find(3) // 递归 find(3): parent[3]4≠3 → 进入if parent[3] find(parent[3]) find(4) // 递归 find(4): parent[4]4 → 返回4 // 回到find(3): parent[3] 4, 返回4 // 回到find(2): parent[2] 4, 返回4 // 回到find(1): parent[1] 4, 返回4递归前 递归后 1 1 ↓ ↓ 2 4 ↓ ↗ ↖ 3 2 3 ↓ 4 (根)合并二、合并过程分解 步骤1分别找根同时压缩 cpp int rootX find(2); // 返回4同时2→4已经是4int rootY find(6); // 返回7同时6→7已经是7 步骤2合并根节点 cpp parent[rootX] rootY; // parent[4] 7 步骤3结果 text 合并后 原集合A1→4, 2→4, 3→4, 4→7 ← 4现在指向7 原集合B5→7, 6→7, 7→7 现在结构 1→4→7 2→4→7 3→4→7 5→7 6→7 7→7根 三、合并后的压缩效果 下次查询时的压缩 如果现在查询节点1 cpp find(1): 初始1→4→7 递归parent[1]4≠1 → parent[1]find(4)find(4): parent[4]7≠4 → parent[4]find(7)find(7): parent[7]7 → 返回7 回到find(4): parent[4]7, 返回7 回到find(1): parent[1]7, 返回7 结果1→7, 4→7路径压缩了 最终完全压缩状态 多次查询后所有节点都直接指向根7 text 1→7 2→7 3→7 4→7 5→7 6→7 7→7确保联通二、为什么 N-1 条边表示连通 图论定理 对于一个有 N 个节点的无向连通图 它的最小生成树恰好有 N-1 条边 如果能选出 N-1 条边连接所有节点 → 图是连通的 如果选不出 N-1 条边 → 图不连通有多个连通分量 直观理解 想象用边把 N 个点连接起来 每连接一个点需要 1 条边 连接 N 个点最少需要 N-1 条边 如果连 N-1 条边都凑不齐说明有些点根本连不上 三、Kruskal算法如何保证判断正确 算法执行过程 cpp int edgesUsed 0; // 已选边数计数器for (int i 0; i M; i) {if (find(u) ! find(v)) { // 如果两点不在同一连通块unite(u, v); // 合并连通块 totalWeight w; edgesUsed; // 计数1if (edgesUsed N - 1) break; // 够了就停}} 两种情况 情况1图连通 text 节点: 1-2-3-4 (共4个节点) 需要的边: 3条 (N-13) 算法过程: 选边(1,2) → edgesUsed1 选边(1,3) → edgesUsed2 选边(1,4) → edgesUsed3 → 停止 最后 edgesUsed 3 N-1 ✓ 情况2图不连通 text 节点: 1-2 3-4 (两个连通分量共4个节点) 最大能选的边: 只能选2条 (1-2, 3-4) 算法过程: 选边(1,2) → edgesUsed1 选边(3,4) → edgesUsed2 再没有边能连接两个分量了 最后 edgesUsed2 N-13 → 不连通2.#includebits/stdc.h using namespace std; int N,M; typedef struct edge{ int u,v,w; }edge; vectorboolenemy; vectorintparent; vectoredgeedges; int find(int x) { if(parent[x]!x) { parent[x]find(parent[x]); } return parent[x]; } bool compare(edge a,edge b) { return a.wb.w; } int main() { cinNM; parent.resize(N); for(int i0;iN;i) parent[i]i; enemy.resize(N,false); for(int i0;iM;i) { int city; cincity; enemy[city]true; } edges.resize(N-1); long long weight0; for(int i0;iN-1;i) { cinedges[i].uedges[i].vedges[i].w; weightedges[i].w; } sort(edges.begin(),edges.end(),compare); long long keep0; for(int i0;iN-1;i) { int uedges[i].u; int vedges[i].v; int wedges[i].w; int rootufind(u); int rootvfind(v); if(!(enemy[rootu]enemy[rootv])) { keepw; if(rootv!rootu) { parent[rootv]rootu; enemy[rootu]enemy[rootv]||enemy[rootu]; } } } coutweight-keependl; }#includebits/stdc.h using namespace std; typedef struct edge{ int u,v,w; }Edge; vectorEdgeedges; vectorintparent; int find(int x) { if(parent[x]!x) { parent[x]find(parent[x]); } return parent[x]; } bool compare(Edge a,Edge b) { return a.w b.w; } int main() { int N,K;cinNK; edges.resize(N-1); parent.resize(N); long long weight0; vectorboolenemy(N,false); for(int i0;iK;i) { int city;cincity; enemy[city]true; } for(int i0;iN-1;i) { cinedges[i].uedges[i].vedges[i].w; weightedges[i].w; } sort(edges.begin(),edges.end(),compare); for(int i0;iN;i) { parent[i]i; } long long keep0; for(int i0;iN-1;i) { int uedges[i].u; int vedges[i].v; int wedges[i].w; int rootufind(u); int rootvfind(v); if(!(enemy[rootu]enemy[rootv])) { keepw; if(rootu!rootv) { parent[rootu]rootv; enemy[rootv]enemy[rootu]||enemy[rootv]; } } } coutweight-keependl; return 0; }树上“隔离敌人”问题详解反向Kruskal思想这道题本质不是普通最小生成树而是树上删边问题因为原图已经是一棵树N 个点 N-1 条边所以不存在“选边连通”而是要“删边分裂”目标是让所有敌人所在的城市互相不连通并且删除代价最小。关键转化思路是与其考虑删哪些边不如考虑保留哪些边因为总权值是固定的删掉的最小 总权值 - 保留的最大于是问题变成在保证“每个连通块最多只有一个敌人”的前提下让保留下来的边权值之和最大。这样就变成一个典型的贪心优先保留权值大的边所以要对边按权值从大到小排序这就是你代码里 compare 写成 a.w b.w 的原因然后用并查集维护连通块同时用 enemy 数组标记这个集合里是否已经有敌人。遍历每一条边 (u, v, w)找到它们的根 rootu 和 rootv如果这两个集合“合并后不会出现两个敌人”也就是不能出现“两个集合都有敌人”那么这条边可以保留并进行合并否则就不能保留相当于把这条边删掉在合并时要同步更新 enemy[root]表示这个新集合是否含敌人。最终 keep 表示保留下来的最大权值和而答案就是 totalWeight - keep。这个问题的本质其实可以一句话总结在树上做“限制条件下的最大生成森林”和普通 Kruskal 的区别只是普通是避免成环这里是避免“一个集合里出现多个敌人”。总结一下核心套路树上问题先想“删边还是留边”删边最小 → 转成留边最大留边最大 → 反向 Kruskal从大到小选再配合并查集 状态标记enemy这类题基本都是这个思路一旦理解这个转化就会非常清晰。

相关文章:

【数据结构与算法】最小生成树Kruskal

1.#include <iostream> #include <algorithm> #include <vector> using namespace std;struct Edge {int u, v, w; // 起点&#xff0c;终点&#xff0c;边权 };vector<Edge> edges; vector<int> parent;// 比较函数&#xff1a;按边权升序排列…...

如何用PortProxyGUI简化Windows端口转发配置

如何用PortProxyGUI简化Windows端口转发配置 【免费下载链接】PortProxyGUI A manager of netsh interface portproxy which is to evaluate TCP/IP port redirect on windows. 项目地址: https://gitcode.com/gh_mirrors/po/PortProxyGUI PortProxyGUI是一款专为Window…...

STM32上如何用串口BREAK中断优雅处理DMX与RDM协议(附完整代码)

STM32串口BREAK中断实现DMX/RDM协议双模通信实战指南 舞台灯光控制系统对实时性和可靠性有着近乎苛刻的要求。作为行业标准的DMX512协议及其扩展协议RDM&#xff0c;承载着数以万计舞台灯具的控制指令。传统基于STM32的软件轮询检测方案常面临响应延迟、误触发等问题&#xff0…...

在 React 中,useRef、ref 属性以及 forwardRef 是处理“引用”(访问 DOM 节点或组件实例)的核心概念

在 React 中&#xff0c;useRef、ref 属性以及 forwardRef 是处理“引用”&#xff08;访问 DOM 节点或组件实例&#xff09;的核心概念。它们经常一起使用&#xff0c;但职责完全不同。以下是它们的核心区别、使用方法及组合示例&#xff1a;1. 核心概念与区别特性ref (属性)u…...

MCP开发环境搭建全攻略(VS Code插件安装避坑白皮书·2024官方认证版)

第一章&#xff1a;MCP开发环境搭建全攻略&#xff08;VS Code插件安装避坑白皮书2024官方认证版&#xff09;前置依赖检查与系统准备 在安装任何 MCP 相关插件前&#xff0c;请确保已安装以下基础组件&#xff1a;VS Code 1.85&#xff08;推荐 1.87.2&#xff09;、Node.js 1…...

GNSS数据处理效率翻倍:FileZilla+crx2rnx自动化脚本一键下载转换RINEX观测值

GNSS数据处理效率革命&#xff1a;构建全自动RINEX观测值处理流水线 凌晨三点的实验室里&#xff0c;李工程师盯着屏幕上堆积如山的.crx文件叹了口气——这已经是本周第三次通宵处理GNSS观测数据了。对于需要处理多站点、长时间序列GNSS数据的科研人员和工程师而言&#xff0c;…...

Python实现简易可信度推理引擎:用20行代码复现经典CF模型

Python实现简易可信度推理引擎&#xff1a;用20行代码复现经典CF模型 在金融风控领域&#xff0c;规则引擎的可信度评估直接影响着决策的准确性。想象一下&#xff0c;当系统需要同时处理多条相互矛盾的交易警报时&#xff0c;如何量化每条证据的可信程度&#xff1f;这正是可…...

AHT20传感器数据漂移?STM32硬件I2C与软件模拟的稳定性对比测试

STM32硬件I2C与软件模拟I2C在AHT20传感器应用中的稳定性深度解析 工业级环境监测系统对温湿度数据的可靠性有着严苛要求。AHT20作为一款高精度温湿度传感器&#xff0c;其数据采集的稳定性直接关系到整个系统的可信度。本文将深入探讨STM32平台下硬件I2C与GPIO模拟I2C两种实现方…...

NetGen:高质量网格生成的科学计算解决方案

NetGen&#xff1a;高质量网格生成的科学计算解决方案 【免费下载链接】netgen netgen: 是一个自动的3D四面体网格生成器&#xff0c;适用于从构造实体几何&#xff08;CSG&#xff09;或STL文件格式的边界表示&#xff08;BRep&#xff09;生成网格。 项目地址: https://git…...

华为AR路由器VRRP配置实战:从单点故障到流量黑洞,一个实验全搞定

华为AR路由器VRRP高可用实战&#xff1a;规避单点故障与流量黑洞的深度解析 在现网架构中&#xff0c;网关设备的可靠性直接决定了整个网络的稳定性。想象一下这样的场景&#xff1a;当核心网关突然宕机&#xff0c;整个办公区的网络瞬间瘫痪&#xff0c;业务系统中断&#xff…...

告别Transformer!用PyTorch从零实现MLP-Mixer图像分类(附完整代码与调参技巧)

告别Transformer&#xff01;用PyTorch从零实现MLP-Mixer图像分类&#xff08;附完整代码与调参技巧&#xff09; 在计算机视觉领域&#xff0c;Transformer架构近年来风头无两&#xff0c;但你是否想过——仅用多层感知机&#xff08;MLP&#xff09;也能构建高性能视觉模型&a…...

图像处理小技巧:如何用Photoshop和Python模拟近红外摄影效果

图像处理小技巧&#xff1a;如何用Photoshop和Python模拟近红外摄影效果 近红外摄影以其独特的视觉效果在艺术创作和科学分析领域广受欢迎。传统的近红外摄影需要特殊滤镜和改装相机&#xff0c;但通过数字图像处理技术&#xff0c;我们完全可以在不改变硬件设备的情况下&#…...

给CUDA新手的3DGS代码导读:从forward.cu到backward.cu,一步步拆解渲染流程

给CUDA新手的3DGS代码导读&#xff1a;从forward.cu到backward.cu&#xff0c;一步步拆解渲染流程 第一次看到3D Gaussian Splatting&#xff08;3DGS&#xff09;的CUDA代码时&#xff0c;我盯着那些复杂的核函数和内存操作发了半小时呆。作为从PyTorch转型过来的研究者&#…...

ArcSWAT实战避坑指南 | 从数据库配置到模型运行,详解常见报错与高效解决方案

1. ArcSWAT入门避坑&#xff1a;从安装到首次运行的关键准备 第一次接触ArcSWAT的水文研究者&#xff0c;往往会在安装环节就踩坑。我见过太多人因为版本兼容性问题&#xff0c;导致后续模型根本无法启动。这里分享几个血泪教训&#xff1a; ArcGIS版本选择是首要关键。虽然官方…...

WPF图片处理避坑指南:Image控件Stretch属性的4种模式详解(含效果对比图)

WPF图片处理避坑指南&#xff1a;Image控件Stretch属性的4种模式详解 刚接触WPF开发的工程师们&#xff0c;是否经常遇到图片显示变形、比例失调的困扰&#xff1f;Image控件的Stretch属性看似简单&#xff0c;却藏着不少设计哲学。今天我们就来彻底拆解这个影响图片显示效果的…...

Next AI Draw.io:从自然语言到专业图表,AI如何重塑技术绘图工作流

1. 当技术绘图遇上AI&#xff1a;一场效率革命 上周三凌晨两点&#xff0c;我还在为一个客户紧急赶制系统架构图。传统绘图工具里反复拖拽调整的机械操作&#xff0c;让我的咖啡消耗量达到了平日的三倍。直到偶然发现Next AI Draw.io这个神器——用一句"生成包含负载均衡和…...

一文讲透|一键生成论文工具:2026年最新测评与推荐大全

2026年真正好用的一键生成论文工具&#xff0c;核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测&#xff0c;千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队&#xff0c;覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。…...

告别低效写作:盘点2026年标杆级的AI论文网站

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文网站&#xff0c;覆盖选题构思、文献整理、内容生成、格式排版全流程&#xff0c;帮你高效搞定论文写作。 一、全流程王者&#xff1a;一站式搞定论文全链路&#xff08;一天定稿首选&#xff…...

数字中国新引擎:产业经济大脑的全景式解构与深度洞察(PPT)

“中国经济高质量发展的核心命题&#xff0c;已从‘有没有’转向‘好不好’。而要回答‘好不好’&#xff0c;就必须构建一套能看清、看准、看远的‘经济慧眼’。”在数字经济成为国家战略主战场的今天&#xff0c;地方政府正面临着前所未有的治理挑战&#xff1a;宏观政策如何…...

从零构建一个轻量级WebSocket服务器:基于libwebsockets的实战与事件循环剖析

从零构建一个轻量级WebSocket服务器&#xff1a;基于libwebsockets的实战与事件循环剖析 在当今实时应用盛行的时代&#xff0c;WebSocket技术已成为构建即时通讯、实时数据推送等功能的基石。不同于传统的HTTP请求-响应模式&#xff0c;WebSocket提供了全双工通信能力&#xf…...

Win11Debloat系统优化工具:从问题诊断到长效维护的完整实践指南

Win11Debloat系统优化工具&#xff1a;从问题诊断到长效维护的完整实践指南 【免费下载链接】Win11Debloat 一个简单的PowerShell脚本&#xff0c;用于从Windows中移除预装的无用软件&#xff0c;禁用遥测&#xff0c;从Windows搜索中移除Bing&#xff0c;以及执行各种其他更改…...

FPGA设计避坑指南:手把手教你搞定跨时钟域信号同步(附Verilog代码)

FPGA设计避坑指南&#xff1a;跨时钟域信号同步的工程实践与Verilog实现 在FPGA开发中&#xff0c;跨时钟域信号同步问题就像电路设计中的"暗礁"&#xff0c;稍有不慎就会导致整个系统崩溃。想象一下这样的场景&#xff1a;你的设计在仿真阶段完美运行&#xff0c;但…...

从Kinect到奥比中光:为什么我的深度学习项目选了Gemini 2L?附Python SDK踩坑实录

从Kinect到奥比中光&#xff1a;为什么我的深度学习项目选了Gemini 2L&#xff1f;附Python SDK踩坑实录 深度视觉技术正在重塑人机交互的边界。当我的团队启动一个需要实时三维重建的农业机器人项目时&#xff0c;我们面临着一个关键抉择&#xff1a;在众多深度相机品牌中&…...

极域电子教室破解神器:JiYuTrainer 让课堂学习更自由高效

极域电子教室破解神器&#xff1a;JiYuTrainer 让课堂学习更自由高效 【免费下载链接】JiYuTrainer 极域电子教室防控制软件, StudenMain.exe 破解 项目地址: https://gitcode.com/gh_mirrors/ji/JiYuTrainer 你是否厌倦了在计算机课堂上被极域电子教室完全控制&#xf…...

NaViL-9B图文问答入门必看:纯文本+图像理解双模式快速上手

NaViL-9B图文问答入门必看&#xff1a;纯文本图像理解双模式快速上手 1. 认识NaViL-9B多模态模型 NaViL-9B是一款原生支持多模态交互的大语言模型&#xff0c;由专业研究团队开发。它最大的特点是能同时处理纯文本问答和图片内容理解任务&#xff0c;就像一个同时精通文字和视…...

CCC 数字钥匙 Release 3:BLE/UWB与NFC融合的无钥匙进入系统解析

1. CCC数字钥匙Release 3的技术革新 想象一下这样的场景&#xff1a;你双手提着购物袋走向爱车&#xff0c;距离3米时车灯自动点亮&#xff0c;1.5米时车门悄然解锁&#xff0c;拉开车门的瞬间引擎已经启动——这就是CCC数字钥匙Release 3带来的无感化体验。作为车联网联盟&…...

FLUX.1文生图优化技巧:SDXL风格节点参数这样调,图片效果更出彩

FLUX.1文生图优化技巧&#xff1a;SDXL风格节点参数这样调&#xff0c;图片效果更出彩 1. 快速上手&#xff1a;FLUX.1文生图工作流基础操作 1.1 工作流启动指南 启动FLUX.1文生图工作流只需简单三步&#xff1a; 在ComfyUI左侧面板找到"FLUX.1-dev-fp8-dit文生图&quo…...

3分钟搞定网易云音乐加密文件:NCMD解密工具终极指南

3分钟搞定网易云音乐加密文件&#xff1a;NCMD解密工具终极指南 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐的NCM加密文件无法在其他播放器播放而烦恼吗&#xff1f;今天我要为你介绍一款简单高效的音频解密神器…...

HeadPose角度检测避坑指南:从原理到车载疲劳预警系统部署

HeadPose角度检测工程实战&#xff1a;车载疲劳预警系统的嵌入式部署精要 引言&#xff1a;当计算机视觉遇上行车安全 凌晨三点的高速公路上&#xff0c;一辆货运卡车正以80公里时速行驶。驾驶座上的王师傅眼皮开始不受控制地下垂&#xff0c;头部微微前倾——这个细微动作被安…...

4个步骤让普通用户实现黑苹果EFI自动生成:OpCore Simplify智能工具全解析

4个步骤让普通用户实现黑苹果EFI自动生成&#xff1a;OpCore Simplify智能工具全解析 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 如何用智能工具解…...