You need to enable JavaScript to run this app. PHP实现可扩展均等分队算法:为带技能的玩家数组划分实力对等两队
优惠活动
大模型
产品
解决方案
定价
更多

PHP实现可扩展均等分队算法:为带技能的玩家数组划分实力对等两队

可扩展均等分队的实现方案

核心设计逻辑

整个算法不绑定固定的20人输入规模,完全基于通用规则实现,后续不管追加多少玩家,只要满足总参赛人数为偶数的基本前提,算法都能正常输出结果,核心思路是通过蛇形分配+偏差微调,把两队的技能总差压到最低,这套逻辑可以直接平移到任意编程语言。

具体实现步骤(PHP适配)

  • 统一玩家数据结构:不管是初始录入的20名玩家,还是后续新增的玩家,都统一为带唯一ID、技能评级的固定结构,追加玩家时仅需往玩家池中append新结构的元素,不需要修改任何算法判断逻辑。
  • 前置校验:判断当前有效参赛总人数是否为偶数,不符合规则时直接抛出业务异常;如果需要支持奇数人数场景,可以预留规则接口(比如指定最低技能值玩家为替补,凑齐偶数人参赛),校验逻辑不依赖固定人数阈值。
  • 全局排序:把所有有效参赛玩家按技能评级从高到低降序排列,不管玩家池规模多大,排序动作都能直接执行,新加入的玩家会自动参与到排序流程中。
  • 蛇形贪心分配:按照排序后的顺序做交叉分配:第1名进A队,第2、3名进B队,第4、5名进A队,第6、7名进B队,循环往复直到所有玩家分配完毕。这种分配方式比直接把排序数组对半切的偏差小很多,能天然避免强队全是高分玩家的问题,且分配规则完全通用,不会因为玩家数量变化失效。
  • 分差微调:计算当前两队的总技能值差,如果差超过预设的可接受阈值,就遍历两队中技能最接近的玩家对,通过交换位置把分差压到阈值内,微调逻辑同样适配任意规模的玩家池。

PHP核心代码

// 可扩展玩家池,后续新增玩家直接往数组中追加即可
$playerPool = [
    ['id' => 1, 'skill' => 7],
    ['id' => 2, 'skill' => 9],
    // 初始20名玩家的录入位置
];

/**
 * 均等分队核心方法
 * @param array $playerPool 全量有效玩家池
 * @param int $maxSkillDiff 允许的两队最大技能分差
 * @return array
 * @throws Exception
 */
function splitTeams(array $playerPool, int $maxSkillDiff = 2): array
{
    $totalCount = count($playerPool);
    // 人数校验,不绑定固定人数阈值
    if ($totalCount % 2 !== 0) {
        throw new Exception('参赛总人数必须为偶数才能均分队伍');
    }
    $perTeamSize = $totalCount / 2;

    // 按技能降序全局排序,自动兼容后续追加的玩家
    usort($playerPool, fn($a, $b) => $b['skill'] <=> $a['skill']);

    // 蛇形分配逻辑
    $teamA = $teamB = [];
    $currentAssignTeam = 'A';
    foreach ($playerPool as $index => $player) {
        // 某队人数凑够阈值就切换到另一队
        if (count(${'team' . $currentAssignTeam}) >= $perTeamSize) {
            $currentAssignTeam = $currentAssignTeam === 'A' ? 'B' : 'A';
        }
        ${'team' . $currentAssignTeam}[] = $player;
        // 每分配2个玩家就切换下一轮的分配目标队,实现蛇形交叉
        if ($index % 2 === 1) {
            $currentAssignTeam = $currentAssignTeam === 'A' ? 'B' : 'A';
        }
    }

    // 分差微调逻辑
    $sumA = array_sum(array_column($teamA, 'skill'));
    $sumB = array_sum(array_column($teamB, 'skill'));
    while (abs($sumA - $sumB) > $maxSkillDiff) {
        $validSwap = null;
        // 找能最大幅度缩小分差的玩家交换对
        foreach ($teamA as $aKey => $aPlayer) {
            foreach ($teamB as $bKey => $bPlayer) {
                $afterSwapDiff = abs(
                    ($sumA - $aPlayer['skill'] + $bPlayer['skill']) 
                    - ($sumB - $bPlayer['skill'] + $aPlayer['skill'])
                );
                if ($afterSwapDiff < abs($sumA - $sumB)) {
                    $validSwap = [
                        'aKey' => $aKey,
                        'bKey' => $bKey,
                        'diff' => $afterSwapDiff
                    ];
                }
            }
        }
        if (!$validSwap) break; // 找不到可缩小分差的交换就终止
        // 执行玩家交换
        [$swapA, $swapB] = [$teamA[$validSwap['aKey']], $teamB[$validSwap['bKey']]];
        $teamA[$validSwap['aKey']] = $swapB;
        $teamB[$validSwap['bKey']] = $swapA;
        // 重新计算两队总技能
        $sumA = $sumA - $swapA['skill'] + $swapB['skill'];
        $sumB = $sumB - $swapB['skill'] + $swapA['skill'];
    }

    return [
        'teamA' => ['members' => $teamA, 'totalSkill' => $sumA],
        'teamB' => ['members' => $teamB, 'totalSkill' => $sumB],
    ];
}

可扩展性说明

  • 新增玩家无侵入:只需要把新玩家的信息按统一格式追加到玩家池,重新调用分队方法即可,哪怕总人数从20扩展到几百都不需要修改核心逻辑。
  • 语言无关:核心的排序、蛇形分配、分差微调逻辑没有绑定PHP专属语法,平移到其他语言时只需要替换对应的数组操作、排序方法即可。
  • 参数可配置:允许的最大分差、队伍人数规则都可以作为方法参数传入,不需要硬编码固定值,适配不同场景的分队要求。

内容的提问来源于stack exchange,提问作者help_me

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.01 00:36:02