使所有节点度数为偶数:LeetCode 周赛 324 T3 奇偶度分类构造法 —— codeforces-go 题解与源码解析
科学计算【免费下载链接】codeforces-go算法竞赛模板库 by 灵茶山艾府 项目地址https://gitcode.com/GitHub_Trending/co/codeforces-go点击查看免费下载导读本文以 codeforces-go 仓库中 LeetCode 周赛 324 第三题Add Edges to Make Degrees of All Nodes Even的题解笔记leetcode/weekly/324/c/README.md为主体完整讲解至多添加两条边使无向图所有节点度数变为偶数的奇偶度分类构造法利用握手定理把问题规约为对奇数度节点的分类讨论m 0、2、4并给出 Python、Java、C、Go 四种语言的完整实现、正确性论证、复杂度分析以及仓库内 Go 源码与本地测试用例的验证全过程。读完本文你将掌握这类度数奇偶性 有限次加边构造题目的通用分析框架。题目问题重述给定一个无向图共有n个节点编号为1到n初始边集为edges。只允许添加至多两条边新加的边不能与已有边重复也不能是自环判断是否存在一种加边方案使得添加后图中每一个节点的度数都变成偶数。这个问题看似需要枚举加边组合但借助图论中的基本事实可以将其化归为对奇数度节点集合的简单分类讨论。核心洞察握手定理与奇度节点的奇偶性设deg(i)表示节点i的度数。根据握手定理无向图中所有节点度数之和等于边数的两倍必然为偶数deg(1) deg(2) … deg(n) 2 × |E|由于等式右边是偶数左边各度数中奇数的个数m也必定是偶数。因此把度数为奇数的节点记入集合oddm |odd|只可能是 0、2、4、6、…每添加一条边(u, v)只会同时改变u、v两个节点的度数奇偶性各翻转一次±1。由以上两点可以立刻排除大部分情况若m ≥ 6由于至多添加两条边最多只能翻转 4 个节点的奇偶性永远无法把所有m个奇度节点全部修正为偶度直接返回false。于是真正需要分析的只有m 0、m 2、m 4三种情形。这里odd只统计有边节点出现在edges中的节点孤立的节点度数为 0是偶数无需处理。分类讨论m 0 / 2 / 4情形一m 0无需加边没有任何奇数度节点图已经符合要求直接返回true。情形二m 2两个奇度节点 x、y记x odd[0]、y odd[1]分两种情况x 与 y 之间没有边直接添加一条边(x, y)两个奇度节点同时变成偶度其余节点度数不变符合要求返回true。x 与 y 之间已经有边不能再重复加这条边。此时必须添加两条边且两条边都必须消耗奇度节点。由于仅剩 x、y 两个奇度节点合理方案是找一个节点i作为中介同时连(x, i)与(y, i)i不在odd中所以deg(i)是偶数加两条边后变为deg(i) 2依然是偶数x、y各加一条边由奇变偶。前提是i与 x、y 之间都没有边否则重复加边非法且i不能等于 x、y 本身。于是枚举[1, n]中所有不为 x、y 的点只要存在i使得(i, x)与(i, y)均不存在就返回true否则返回false。为什么 m 2 且已有边时只能走中介方案因为两条边若都连在两个偶度节点之间会把它们变成奇度节点得不偿失若与 x 或 y 重复相连则非法。所以唯一可行的两条边结构就是(x, i)、(y, i)这与枚举逻辑完全对应。情形三m 4四个奇度节点 a、b、c、d记a, b, c, d odd[0..3]。此时需要添加两条边把四个奇度节点两两配对每对之间连一条边四个节点的度数就都变回偶数。共有三种配对方式(a, b)与(c, d)(a, c)与(b, d)(a, d)与(b, c)只要某一组配对中的两条边都没有出现在原图中不允许重复加边即可返回true三种配对都行不通则返回false。return (b∉adj[a] 且 d∉adj[c]) // 配对 1 或 (c∉adj[a] 且 d∉adj[b]) // 配对 2 或 (d∉adj[a] 且 c∉adj[b]) // 配对 3其余情形m ≥ 6如前所述两条边最多修正 4 个奇度节点m ≥ 6时必然无解返回false。至此分类讨论完整闭合。多语言参考实现以下代码原样继承自题解笔记leetcode/weekly/324/c/README.md四种语言的逻辑完全一致均采用邻接集合表示图、遍历节点统计奇度集合、再按m分类判断。Python3class Solution: def isPossible(self, n: int, edges: List[List[int]]) - bool: g defaultdict(set) for x, y in edges: g[x].add(y) g[y].add(x) odd [i for i, nb in g.items() if len(nb) % 2] m len(odd) if m 0: return True if m 2: x, y odd return x not in g[y] or any( i ! x and i ! y and x not in g[i] and y not in g[i] for i in range(1, n 1)) if m 4: a, b, c, d odd return b not in g[a] and d not in g[c] or \ c not in g[a] and d not in g[b] or \ d not in g[a] and c not in g[b] return FalseJavaclass Solution { public boolean isPossible(int n, ListListInteger edges) { var g new Set[n 1]; Arrays.setAll(g, e - new HashSetInteger()); for (var e : edges) { int x e.get(0), y e.get(1); g[x].add(y); g[y].add(x); } var odd new ArrayListInteger(); for (var i 1; i n; i) if (g[i].size() % 2 0) odd.add(i); var m odd.size(); if (m 0) return true; if (m 2) { int x odd.get(0), y odd.get(1); if (!g[x].contains(y)) return true; for (var i 1; i n; i) if (i ! x i ! y !g[i].contains(x) !g[i].contains(y)) return true; return false; } if (m 4) { int a odd.get(0), b odd.get(1), c odd.get(2), d odd.get(3); return !g[a].contains(b) !g[c].contains(d) || !g[a].contains(c) !g[b].contains(d) || !g[a].contains(d) !g[b].contains(c); } return false; } }Cclass Solution { public: bool isPossible(int n, vectorvectorint edges) { unordered_setint g[n 1]; for (auto e : edges) { int x e[0], y e[1]; g[x].insert(y); g[y].insert(x); } vectorint odd; for (int i 1; i n; i) if (g[i].size() % 2) odd.push_back(i); int m odd.size(); if (m 0) return true; if (m 2) { int x odd[0], y odd[1]; if (!g[x].count(y)) return true; for (int i 1; i n; i) if (i ! x i ! y !g[i].count(x) !g[i].count(y)) return true; return false; } if (m 4) { int a odd[0], b odd[1], c odd[2], d odd[3]; return !g[a].count(b) !g[c].count(d) || !g[a].count(c) !g[b].count(d) || !g[a].count(d) !g[b].count(c); } return false; } };Go仓库同款实现仓库中的正式实现位于 leetcode/weekly/324/c/c.go用map[int]map[int]bool构建邻接集合func isPossible(n int, edges [][]int) bool { g : map[int]map[int]bool{} for _, e : range edges { x, y : e[0], e[1] if g[x] nil { g[x] map[int]bool{} } g[x][y] true if g[y] nil { g[y] map[int]bool{} } g[y][x] true } odd : []int{} for i, nb : range g { if len(nb)%2 0 { odd append(odd, i) } } m : len(odd) if m 0 { return true } if m 2 { x, y : odd[0], odd[1] if !g[x][y] { return true } for i : 1; i n; i { if i ! x i ! y !g[i][x] !g[i][y] { return true } } return false } if m 4 { a, b, c, d : odd[0], odd[1], odd[2], odd[3] return !g[a][b] !g[c][d] || !g[a][c] !g[b][d] || !g[a][d] !g[b][c] } return false }值得注意的 Go 实现细节!g[x][y]在x不在g中时会读取nilmap 的键Go 对nilmap 的读取返回零值false因此不存在越界或 panic 风险天然满足无边即返回 true的语义。另外odd的收集只需遍历g有边节点而 m 2 情形中枚举中介点i时需要覆盖[1, n]的全部节点——包括孤立节点因为孤立点度数恒为 0偶数完全有资格充当中介这一枚举范围正是分类讨论正确性的关键一环。仓库内的测试验证在讲解算法之外仓库还提供了一套完整的本地测试链路可用于亲手验证实现测试入口 leetcode/weekly/324/c/c_test.go 调用testutil.RunLeetCodeFuncWithFile(t, isPossible, c.txt, targetCaseNum)从文本文件按组读取输入输出用例文件 leetcode/weekly/324/c/c.txt 以函数入参 期望输出分组存放其解析逻辑位于 leetcode/testutil/leetcode.go先剔除空行再利用反射获取函数的入参/出参个数fNumIn、fNumOut按fNumIn fNumOut行一组切分成用例最终逐个断言输出。用c.txt中的三个用例可以完整走一遍分类讨论的分支用例输入分类走向结果1n5边[[1,2],[2,3],[3,4],[4,2],[1,4],[2,5]]度数 4 为 3、5 为 1odd{4,5}m2且 4、5 之间无边直接连(4,5)true2n4边[[1,2],[3,4]]四个节点度数全为 1odd{1,2,3,4}m4配对(1,3)(2,4)均无现成边true3n4边[[1,2],[1,3],[1,4]]节点 1 度数为 3其余为 1odd{1,2,3,4}m4三种配对都至少包含一条已有边无解false第 3 个用例正是 m 4 分支的典型反例星形图中心节点 1 已与 2、3、4 全部相连无论哪两种配对都会撞上已存在的边因而无法加边验证了三种配对全部失败即返回 false的必要性。复杂度分析时间复杂度O(n m)其中m为edges的长度。建图与统计奇度节点各需一次线性扫描m 2 时最坏情况下遍历[1, n]全部节点一次仍为线性。空间复杂度O(n m)用于存储邻接集合g与奇度集合odd。小结一类度数奇偶性 有限加边题目的通用套路本题的解法具有很好的迁移性其分析链条可以总结为四步通用框架用握手定理确认奇数度节点个数m必为偶数排除m ≥ 2k2的大规模无解情形k为可加边数上限本题k 2把加边看作奇偶性翻转一条边翻转两个端点的奇偶性由此确定每条新边必须命中至少一个奇度节点按 m 的取值分类讨论m 0 直接成功、m 2 要么一条直连要么找偶度中介连两条、m 4 则枚举三种配对补全边界检查不允许重复加边、不允许自环是每步判断无边的前提。仓库中同场次的其余题目a.go 的字符掩码计数、b.go 的质因数分解迭代、d.go 的完全二叉树环长查询与本题共同展示了对图论/数论结构做精细分类讨论的周赛解题风格而 c.go 与 c_test.go 则展示了算法竞赛代码如何在仓库中以源码 数据文件 反射驱动测试的方式沉淀与回归验证。赞分享科学计算【免费下载链接】codeforces-go算法竞赛模板库 by 灵茶山艾府 项目地址https://gitcode.com/GitHub_Trending/co/codeforces-go点击查看免费下载相关推荐codeforces-go 题解LeetCode 第 112 场双周赛「通过操作使字符串相等 II」的奇偶分组计数法codeforces go 题解LeetCode 第 112 场双周赛「通过操作使字符串相等 II」的奇偶分组计数法 本篇以 codeforces go 仓库科学计算LeetCode 324 摆动排序 II 题解倒序排序 奇偶索引分置的构造法LeetCode 324 摆动排序 II 题解倒序排序 奇偶索引分置的构造法 导读 本题是 LeetCode 324「摆动排序 II」属于典型的 构造类文档教程知识库AnimatedDrawings 实用指南把手绘小人做成可导出的动画 GIFAnimatedDrawings 实用指南把手绘小人做成可导出的动画 GIF 孩子纸上画了个小人你想看这个小人跳舞用 AnimatedDrawings 就科学计算上一篇GhostNetV2模型安全指南如何保护你的AI模型不被攻击下一篇ReClip高清视频怎么选4K/1080p/720p选择指南与体积对比全解创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

12GB 显存把 Qwen-Image-2.1 变成局域网生图服务:HTTP API 发布实战(RTX 3060 实测)

12GB 显存把 Qwen-Image-2.1 变成局域网生图服务:HTTP API 发布实战(RTX 3060 实测)

12GB 显存把 Qwen-Image-2.1 变成局域网生图服务:HTTP API 发布实战(RTX 3060 实测) 【免费下载链接】Qwen-Image-2.1-GGUF 项目地址: https://ai.gitcode.com/hf_mirrors/abenzerps/Qwen-Image-2.1-GGUF Qwen-Image-2.1 是阿里千问开…

2026/10/10 11:24:25 阅读更多 →
Python类怎么写才顺手?从封装继承到dataclass最佳实践

Python类怎么写才顺手?从封装继承到dataclass最佳实践

说个demo代码,逻辑清清楚楚,一点问题没有。说辞维系在一个类里,翻页、缓存、用户偏好全塞进去,形形色色的状态互相牵扯,越写越累。后来我意识到问题不在“类”这工具上,而是我把Python类写成了Java味——重…

2026/10/10 11:24:24 阅读更多 →
Apache Spark PySpark:spark.conf 运行时配置接口(RuntimeConfig)完全解析

Apache Spark PySpark:spark.conf 运行时配置接口(RuntimeConfig)完全解析

大数据数据分析批处理流处理机器学习图计算 【免费下载链接】spark Apache Spark - A unified analytics engine for large-scale data processing 项目地址: https://gitcode.com/gh_mirrors/sp/spark 点击查看 免费下载 spark.conf 是 PySpark 中在运行时读取、设…

2026/10/10 11:24:22 阅读更多 →

最新新闻

热电联产机组联合优化调度:Matlab+YALMIP建模风电消纳与储热电锅炉算例

热电联产机组联合优化调度:Matlab+YALMIP建模风电消纳与储热电锅炉算例

1. 冬季供暖季的弃风困局:热电联产机组到底卡在哪每年供暖季一过,风电场的同事就开始盯着调度曲线叹气:白天风光还好,一到后半夜风速上来了,风电场却得压出力,甚至有整场停机的时候。而另一边,热…

2026/10/10 16:01:52 阅读更多 →
用AI高效阅读鸿蒙源码:仓库定位、调用链与实战技巧

用AI高效阅读鸿蒙源码:仓库定位、调用链与实战技巧

简介:面向鸿蒙OS平台的“阅读”应用鸿蒙版仓库源码,特别适合鸿蒙应用开发者、对小说阅读器实现感兴趣的工程师,以及希望复用书源管理方案的技术人员。工程基于ArkTS编写主要页面与业务逻辑,并搭配svg、png等图标与图片资源&#x…

2026/10/10 16:01:52 阅读更多 →
Java IO流深度解析:字节流字符流、缓冲流与序列化实战指南

Java IO流深度解析:字节流字符流、缓冲流与序列化实战指南

1. 别被IO流的类图吓到:先搞懂设计骨架做Java开发几年后回头看,IO流其实是整个Java生态里设计最经典、也最劝退新手的模块之一。所谓“Java进阶--IO流”,不是让你把几十个类的名字背下来,而是先看清这套体系背后的两个核心设计思想…

2026/10/10 16:01:52 阅读更多 →
Vector v0.51.0 版本深度解析:OTLP 编解码、file source 去遗留化与遥测可靠性加固

Vector v0.51.0 版本深度解析:OTLP 编解码、file source 去遗留化与遥测可靠性加固

可观测性数据工程数据集成日志分析 【免费下载链接】vector A high-performance observability data pipeline. 项目地址: https://gitcode.com/GitHub_Trending/vect/vector 点击查看 免费下载 Vector v0.51.0(发布于 2025-11-04)是面向可观…

2026/10/10 16:01:52 阅读更多 →
Spring AI 2.x 深度技术解析:从架构重构到企业级落地,TaoToken 统一 Key 接入实践

Spring AI 2.x 深度技术解析:从架构重构到企业级落地,TaoToken 统一 Key 接入实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 16:01:52 阅读更多 →
探索AI工具——我的Cursor初体验:从Base URL改到TaoToken

探索AI工具——我的Cursor初体验:从Base URL改到TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 16:00:51 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:25 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →