资讯动态

贪心算法与双指针法解决田忌赛马问题

发布时间:2026/10/26 3:52:48 来源:尧图企业网站定制
1. 问题背景与题目解析洛谷B3928这道题改编自经典的田忌赛马故事要求我们通过编程解决一个策略优化问题。题目给定田忌和齐王各自拥有N匹马每匹马有一个固定的速度值。比赛规则是双方每次各派出一匹马进行比拼速度快的马获胜败者淘汰。我们需要设计一个算法计算出田忌最多能赢多少场比赛。这道题之所以被归类为GESP四级考题是因为它完美融合了三个核心算法思想排序对双方马匹速度进行有序排列双指针高效匹配双方马匹贪心在每一步做出局部最优选择在实际编程竞赛和面试中这类问题非常常见。2023年字节跳动的校招笔试中就出现过类似的马匹匹配问题而亚马逊的面试题库里也有基于此题的变种。2. 算法设计思路2.1 基础贪心策略最直观的贪心策略是将田忌和齐王的马分别按速度排序用田忌最快的马对齐王最快的马如果田忌的快就用这匹赢一场如果田忌的慢就用最差的马消耗对方最好的马这个策略在大多数情况下有效但存在一个关键缺陷当田忌最快的马和齐王最快的马速度相同时直接比拼会导致平局可能浪费优势资源。2.2 改进的双指针策略更优的解法采用双指针法将双方马匹都按速度升序排序初始化四个指针ti田忌当前最好的马tj田忌当前最差的马qi齐王当前最好的马qj齐王当前最差的马比较田忌最差的马和齐王最差的马如果田忌的更差直接用它消耗齐王最好的马如果田忌的更好先赢下这一场如果速度相同再比较双方最好的马这种策略确保我们在每一步都做出局部最优选择同时避免了无谓的平局。3. 代码实现细节3.1 C实现示例#include iostream #include algorithm using namespace std; int main() { int n; cin n; int tian[n], qi[n]; for(int i0; in; i) cin tian[i]; for(int i0; in; i) cin qi[i]; sort(tian, tiann); sort(qi, qin); int t_head0, t_tailn-1; int q_head0, q_tailn-1; int wins 0; while(t_head t_tail) { if(tian[t_tail] qi[q_tail]) { wins; t_tail--; q_tail--; } else if(tian[t_tail] qi[q_tail]) { t_head; q_tail--; } else { if(tian[t_head] qi[q_head]) { wins; t_head; q_head; } else { if(tian[t_head] qi[q_tail]) { t_head; q_tail--; } else { t_head; q_tail--; } } } } cout wins endl; return 0; }3.2 关键代码解析排序部分使用STL的sort函数对双方马匹进行升序排序时间复杂度O(nlogn)这是算法的主要时间消耗双指针逻辑t_head/t_tail管理田忌当前可用马匹范围q_head/q_tail管理齐王当前可用马匹范围每次循环处理一对马的比较胜负判断优先比较双方最好的马当最好的马相同时比较最差的马确保每次操作至少淘汰一匹马4. 算法复杂度分析4.1 时间复杂度排序阶段O(nlogn)双指针匹配阶段O(n)总体复杂度O(nlogn)这个复杂度对于n≤10^5的数据规模完全适用这也是题目给出的典型数据范围。4.2 空间复杂度只需要存储两个数组O(n)排序可能使用O(logn)的栈空间取决于sort实现总体空间复杂度O(n)5. 边界条件与测试用例5.1 常见边界情况所有马速度相同应返回0因为无法赢得任何比赛田忌所有马都比齐王慢应返回0田忌所有马都比齐王快应返回n单匹马情况直接比较两匹马速度5.2 测试用例设计// 普通情况 输入 3 92 83 71 95 87 74 输出 1 // 田忌全胜 输入 4 10 20 30 40 5 15 25 35 输出 4 // 平局情况 输入 3 10 10 10 10 10 10 输出 0 // 混合情况 输入 5 10 20 30 40 50 15 25 35 45 55 输出 26. 算法优化与变种6.1 性能优化技巧输入输出优化对于大规模数据使用更快的IO方式例如C中的ios::sync_with_stdio(false)提前终止当田忌剩余马匹不可能再获胜时提前结束循环内存访问优化确保数组访问是连续的考虑缓存友好性6.2 问题变种带权重的版本每场比赛有不同的奖金需要最大化总奖金而非胜场数多队伍竞赛扩展为多个队伍相互比赛需要更复杂的匹配策略动态马匹马匹速度可以临时调整引入动态规划思想7. 实际应用场景这种算法思想在以下场景中有广泛应用资源调度将有限资源分配给最合适的任务例如云计算中的虚拟机分配广告竞价将广告与用户点击概率最佳匹配类似马匹与胜率的对应关系赛事安排体育比赛中的选手匹配确保比赛竞争性和观赏性负载均衡将任务分配给最合适的服务器类似于匹配马匹速度8. 常见错误与调试技巧8.1 典型错误排序方向错误升序和降序混淆导致指针移动方向错误平局处理不当直接当作胜负处理浪费优势资源指针越界循环条件设置不当导致数组访问越界8.2 调试建议小规模测试先用n2,3的简单案例验证打印中间状态输出每次循环后的指针位置和胜负情况边界测试专门测试全胜、全败、全平等极端情况对拍测试生成随机数据与暴力解法对比9. 学习资源推荐算法书籍《算法导论》中的贪心算法章节《编程之美》中的类似问题在线资源LeetCode上的Two Sum等双指针问题Codeforces上的贪心算法专题竞赛题目POJ 2287 田忌赛马原题HDU 1052 类似题目可视化工具VisuAlgo 算法可视化平台Algorithm Visualizer10. 个人实战经验在实际编程竞赛中这类题目有几个关键点需要注意变量命名使用有意义的变量名如tianji_head而非简单的i,j减少调试时的认知负担代码结构将核心逻辑提取为单独函数增强代码可读性测试驱动先写测试用例再实现算法确保覆盖所有边界情况性能分析使用profiler分析热点重点优化排序部分我在一次线上比赛中就因为没有正确处理平局情况而失分。后来通过添加专门的平局处理分支成功通过了所有测试点。这也提醒我们贪心算法的细节处理往往决定成败。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑