贪心算法解决空手道比赛匹配问题

📅 2026/7/19 1:22:15
贪心算法解决空手道比赛匹配问题
1. 题目背景与问题解析LightOJ 1198 Karate Competition是一道经典的贪心算法练习题题目场景设定在空手道比赛中。我们需要为两支队伍你的队伍和对手队伍的选手进行匹配通过合理的对战安排来最大化己方的得分。比赛规则的核心是每支队伍有N名选手每位选手都有一个确定的实力值当你的选手与对方选手对战时你的选手实力值 对方得2分你的选手实力值 对方得1分你的选手实力值 对方得0分2. 贪心算法思路分析2.1 贪心策略的选择这道题属于典型的田忌赛马类问题最优解通常需要采用贪心策略。我们需要考虑以下几种可能的匹配方式用己方最强的选手对战对方最强的选手用己方最弱的选手对战对方最弱的选手用己方最弱的选手消耗对方最强的选手经过分析正确的贪心策略应该是首先尝试用己方最强的选手击败对方最强的选手当无法击败时用己方最弱的选手消耗对方最强的选手特别注意处理实力相等的情况2.2 算法步骤详解具体实现步骤如下对两支队伍的实力值分别进行排序升序或降序均可但需要保持一致初始化四个指针my_low己方最弱选手位置my_high己方最强选手位置opp_low对方最弱选手位置opp_high对方最强选手位置循环比较直到所有选手完成匹配 a. 如果己方最强 对方最强直接对战得2分双方最强指针都向内移动 b. 如果己方最强 对方最强用己方最弱消耗对方最强得0分己方最弱指针右移对方最强指针左移 c. 如果实力相等比较双方最弱的选手如果己方最弱 对方最弱用己方最弱对战对方最弱得2分双方最弱指针都右移否则用己方最弱消耗对方最强得1分如果相等或0分3. 代码实现与优化3.1 基础实现以下是C的基础实现代码框架#include algorithm #include vector using namespace std; int karateCompetition(vectorint myTeam, vectorint oppTeam) { sort(myTeam.begin(), myTeam.end()); sort(oppTeam.begin(), oppTeam.end()); int score 0; int my_low 0, my_high myTeam.size() - 1; int opp_low 0, opp_high oppTeam.size() - 1; while (my_low my_high) { if (myTeam[my_high] oppTeam[opp_high]) { score 2; my_high--; opp_high--; } else if (myTeam[my_high] oppTeam[opp_high]) { if (myTeam[my_low] oppTeam[opp_low]) { score 2; my_low; opp_low; } else { if (myTeam[my_low] oppTeam[opp_high]) score 1; my_low; opp_high--; } } else { if (myTeam[my_low] oppTeam[opp_low]) { score 2; my_low; opp_low; } else { if (myTeam[my_low] oppTeam[opp_high]) score 1; my_low; opp_high--; } } } return score; }3.2 代码优化技巧减少条件判断可以合并一些相似的条件分支提前终止当己方剩余选手不可能再得分时可以提前结束循环空间优化如果不需要保留原数组可以直接在原数组上操作优化后的代码示例int karateCompetition(vectorint myTeam, vectorint oppTeam) { sort(myTeam.begin(), myTeam.end()); sort(oppTeam.begin(), oppTeam.end()); int score 0; int i 0, j 0; int x myTeam.size() - 1, y oppTeam.size() - 1; while (i x) { if (myTeam[x] oppTeam[y]) { score 2; x--; y--; } else if (myTeam[x] oppTeam[y]) { if (myTeam[i] oppTeam[j]) { score 2; i; j; } else { if (myTeam[i] oppTeam[y]) score 1; i; y--; } } else { if (myTeam[i] oppTeam[j]) { score 2; i; j; } else { if (myTeam[i] oppTeam[y]) score 1; i; y--; } } } return score; }4. 复杂度分析与边界条件4.1 时间复杂度算法的主要时间消耗在于排序排序时间复杂度O(n log n)贪心匹配过程O(n)总体时间复杂度O(n log n)4.2 空间复杂度如果可以在原数组上排序O(1)如果需要额外空间O(n)4.3 边界条件处理需要特别注意以下边界情况空输入两队都无选手两队选手数量不等题目通常保证N相等所有选手实力完全相同的情况己方完全强于或完全弱于对方的情况测试用例示例void test() { vectorint my1 {5, 8, 10}, opp1 {6, 7, 9}; // 应得4分 vectorint my2 {10, 10, 10}, opp2 {10, 10, 10}; // 应得3分 vectorint my3 {1, 2, 3}, opp3 {4, 5, 6}; // 应得0分 vectorint my4 {5}, opp4 {5}; // 应得1分 cout karateCompetition(my1, opp1) endl; cout karateCompetition(my2, opp2) endl; cout karateCompetition(my3, opp3) endl; cout karateCompetition(my4, opp4) endl; }5. 贪心算法的正确性证明5.1 贪心选择性质我们需要证明每一步的贪心选择都能导致全局最优解当己方最强 对方最强时用己方最强击败对方最强是最优选择因为这样既获得了2分又不会浪费己方强选手当己方最强 对方最强时用己方最弱消耗对方最强是最优选择因为己方最弱在其他情况下可能得更多分当实力相等时比较最弱的选手如果己方最弱 对方最弱先得这2分否则用己方最弱消耗对方最强5.2 最优子结构性质每次做出贪心选择后剩下的子问题与原问题具有相同的性质可以通过相同的策略解决。6. 类似问题与扩展6.1 类似题目推荐LeetCode 870. Advantage ShufflePOJ 2287 Tian Ji - The Horse RacingCodeForces 725D Contest Balloons6.2 问题变种思考如果比赛规则改变如不同的得分规则该如何调整算法如果选手实力可能相同但数量不等如何处理如果允许部分选手不参赛如何最大化得分6.3 实际应用场景这种类型的贪心算法在实际中有广泛应用资源分配问题任务调度优化竞标策略制定体育比赛排兵布阵7. 常见错误与调试技巧7.1 常见实现错误排序方向错误必须确保双方排序顺序一致指针移动错误特别是在处理相等情况时得分计算错误容易混淆1分和2分的条件循环终止条件错误应该是己方选手全部匹配完7.2 调试建议打印中间状态在每次匹配后打印当前指针位置和得分小规模测试先用手算验证小规模测试用例边界测试专门测试全相等、全大于、全小于的情况随机测试生成随机数据与暴力解法对比调试示例代码int karateCompetitionDebug(vectorint myTeam, vectorint oppTeam) { sort(myTeam.begin(), myTeam.end()); sort(oppTeam.begin(), oppTeam.end()); cout Sorted my team: ; for (int num : myTeam) cout num ; cout \nSorted opp team: ; for (int num : oppTeam) cout num ; cout endl; int score 0; int i 0, j 0; int x myTeam.size() - 1, y oppTeam.size() - 1; while (i x) { cout Current: my[ i , x ], opp[ j , y ] endl; if (myTeam[x] oppTeam[y]) { cout myTeam[x] oppTeam[y] , 2 endl; score 2; x--; y--; } else if (myTeam[x] oppTeam[y]) { if (myTeam[i] oppTeam[j]) { cout myTeam[i] oppTeam[j] , 2 endl; score 2; i; j; } else { if (myTeam[i] oppTeam[y]) { cout myTeam[i] oppTeam[y] , 1 endl; score 1; } else { cout myTeam[i] oppTeam[y] , 0 endl; } i; y--; } } else { if (myTeam[i] oppTeam[j]) { cout myTeam[i] oppTeam[j] , 2 endl; score 2; i; j; } else { if (myTeam[i] oppTeam[y]) { cout myTeam[i] oppTeam[y] , 1 endl; score 1; } else { cout myTeam[i] oppTeam[y] , 0 endl; } i; y--; } } cout Current score: score endl endl; } return score; }8. 算法优化与进阶思考8.1 进一步优化方向使用更高效的排序算法如基数排序如果数据范围有限并行处理排序和匹配过程使用双端队列(deque)代替数组和指针8.2 贪心算法的局限性虽然贪心算法在这里有效但它并不适用于所有问题需要问题具有贪心选择性质需要问题具有最优子结构不能回退一旦做出选择就不能改变8.3 其他解法探讨这道题也可以使用动态规划解决但时间复杂度会更高定义dp[i][j]表示用前i个己方选手对前j个对方选手的最大得分状态转移方程需要考虑多种匹配情况时间复杂度O(n^2)不如贪心算法高效