查询以获得2个相同的队伍

时间:2013-01-14 10:23:29

标签: php mysql database combinations

我有一个女巫看起来像这样:

----------------------------------------
| index | players | date       | score |
----------------------------------------
|   1   | jan     | 2013-01-13 |   5   |
----------------------------------------
|   2   | piet    | 2013-01-13 |   6   |
----------------------------------------
|   3   | klaas   | 2013-01-13 |   5   |
----------------------------------------
|   4   | kees    | 2013-01-13 |   7   |
----------------------------------------
|   5   | william | 2013-01-13 |   8   |
----------------------------------------
|   6   | john    | 2013-01-13 |   4   |
----------------------------------------

现在我想做一些棘手的事情,为了像2013-01-14的比赛一样打下一场比赛,我们想让2支球队成为平等的球队。

每个日期有12名球员,所以2013-01-13是12名球员,而在2013-01-14还有相同的球员。

他们必须离婚成2支球队,所以12/2 = 6人。现在这不是问题,问题是两支球队的总得分必须相等或相近。

如果12名球员的所有得分都是77,则两队的总得分必须几乎相等,如77/2 = 38,5

  队伍1 - 队员6 - 总成绩37

     

第2队 - 队员6 - 总分40

最后,查询输出必须如下:

-----------------------------------------------
| index | players | date       | score | team |
-----------------------------------------------
|   1   | jan     | 2013-01-13 |   5   |   1  |
-----------------------------------------------
|   2   | piet    | 2013-01-13 |   6   |   1  |
-----------------------------------------------
|   3   | klaas   | 2013-01-13 |   8   |   1  |
-----------------------------------------------
|   4   | kees    | 2013-01-13 |   7   |   1  |
-----------------------------------------------
|   5   | william | 2013-01-13 |   5   |   1  |
-----------------------------------------------
|   6   | john    | 2013-01-13 |   6   |   1  |
-----------------------------------------------
|   7   | gerrit  | 2013-01-13 |   6   |   2  |
-----------------------------------------------
|   8   | maartje | 2013-01-13 |   6   |   2  |
-----------------------------------------------
|   9   | shara   | 2013-01-13 |   8   |   2  |
-----------------------------------------------
|  10   | els     | 2013-01-13 |   7   |   2  |
-----------------------------------------------
|  11   | allen   | 2013-01-13 |   5   |   2  |
-----------------------------------------------
|  12   | steven  | 2013-01-13 |   8   |   2  |
-----------------------------------------------

-----------------------------------------------
|  team     | score    | date       | players |
-----------------------------------------------
|  Team 1   | 37       | 2013-01-13 |    6    |
-----------------------------------------------
|  Team 2   | 40       | 2013-01-13 |    6    |
-----------------------------------------------

借助#Danack的灵感,我做到了这一点:

$difference = 10;
$team_smnstlln = array();
for($q=0; $q<1000; $q++){

    $players = array();

    $team_smnstlln[$q] = array(
                                'team1' => array(),
                                'team2' => array(),
                                'total' => 0
                              );

    $count1 = 0;
    for($w=0; $w<6; $w++){
        $player = pick_random(true);
        $score1 = $team_smnstlln[$q]['team1'][$player] = $data[$player]['score'];
        $count1 = $count1 + $score1;
    }

    $count2 = 0;
    for($w=6; $w<12; $w++){
        $player = pick_random(true);
        $score2 = $team_smnstlln[$q]['team2'][$player] = $data[$player]['score'];
        $count2 = $count2 + $score2;
    }

    if($count1 > $count2){
        $total = $count1 - $count2;
    }
    elseif($count2 > $count1){
        $total = $count2 - $count1;
    }
    else{
        $total = 0;
    }

    $team_smnstlln[$q]['total'] = $total;

    if($team_smnstlln[$q]['total'] == 0){
        $difference = 0;
        $winner = $q;
        break;
    }
    elseif($team_smnstlln[$q]['total'] < $difference){
        $difference = $team_smnstlln[$q]['total'];
        $winner = $q;
    }

}

echo "Kleinst gekozen set met score verschil van $difference punten. array $winner is gekozen<br>";

$team1 = $team_smnstlln[$winner]['team1'];
$team2 = $team_smnstlln[$winner]['team2'];

print_r($team1);
print_r($team2);

// random player picker

function pick_random($gonogo){

    global $players;

    $go = true;
    $total_players = 11;

    while($go){

        $player = rand(0, $total_players);

        if(!in_array($player, $players)){
            $players[] = $player;
            $go = false;
        }

    }

    return $player;

}

此代码运行1000个不同的团队设置。当得分差为0时,它将停止回应最佳平等的队伍比赛。否则,当没有0差异时,它将返回最低结果

3 个答案:

答案 0 :(得分:4)

正如moonwave99所说,在PHP中执行此操作比尝试在SQL中执行此操作要好得多。

问题在于这是一个难以解决的问题。您可以通过重新询问您的问题来看到:

“1支队伍中的6名队员和其他队伍中的6名队员的组合将在分数上有最小的差异?”

从12个中挑选6个玩家的组合数量是(12!/ 6!)或665,280个组合,每个组合都需要计算得分。

您需要完成所有可能的组合,并计算每个组合的得分以找到“最佳”组合。

//An array to record whether each player has already been selected for a combination
$playersChosen = array();

//Initialise the array
for($x=0 ; $x<12 ; $x++){
    $playersChosen[$x] = FALSE;
}

//Need to store lowest score somewhere - and have a flag for the first calculation
$lowestScore = FALSE;


chooseAnotherPlayer(6, 0);

//$GLOBALS['bestCombination'] - will now contain the best combination of players.


//Recursive function that either:
//goes through each player in turn and then calls itself or 
//calculates the 'score' when all the players are chosen for one team
//$playersToChoose - how many players left to choose.
//$minimumPlayerNumber - index to start searching for players not yet chosen - as the choice,  3 + 5 is identical to 5 + 3
function chooseAnotherPlayer($playersToChoose, $minimumPlayerNumber){

    //We have 6 pl
    if($playersToChoose == 0){
        //Calculate Score from which players are selected in $GLOBALS['playersChosen']
        if($lowestScore === FALSE ||
            $score < $lowestScore){
            $GLOBALS['bestCombination'] = $GLOBALS['playersChosen'];  //Arrays are copied by value, not reference
//So this saves a snapshot of the best selection.
        }
        return;
    }

    //Go through each of the players
    for($x=$minimumPlayerNumber ; $x<12; $x++){
        //Select them if they're available
        $playerAvailable = selectPlayer($x);
        if($playerAvailable == TRUE){
                    //Pick another player
            chooseAnotherPlayer($playersToChose - 1, $x + 1);
                    //Release this player, so he's available for other combinations
            unselectPlayer($x);
        }
    }
}

function selectPlayer($x){
    if($GLOBALS['playersChosen'][$x] == TRUE){
        //Player has already been selected in this combination.
        return FALSE;
    }

    return TRUE;
}

如果您不介意花几秒钟处理该代码将完全解决您的问题。但是,如果您需要快速,那么您最好随机选择团队,评估“得分”并进行足够的迭代以获得合理的结果。

$playersChosen = array();

resetArray();

$playersToChose = 6;
$lowestScore = FALSE;

for($n=0 ; $n<10000 ; $n++){
    chooseAnotherPlayers(6);
    resetArray();
}

function chooseAnotherPlayer($playersToChoose){

    if($playersToChoose == 0){
        //Calculate Score from which players are selected in $GLOBALS['playersChosen']
        if($lowestScore === FALSE ||
            $score < $lowestScore){
            $GLOBALS['bestCombination'] = $GLOBALS['playersChosen'];
            return;
        }
    }

    selectPlayerAtRandom($x);
    chooseAnotherPlayer($playersToChose - 1);
}

function selectPlayer($x){

    $playerSelected = FALSE;

    while($playerSelected == FALSE){

        $x = rand(0, 12 - 1);

        if($GLOBALS['playersChosen'][$x] == FALSE){
            $GLOBALS['playersChosen'][$x] = TRUE;
            return $x;
        }    
    }

}

function resetArray(){
    for($x=0 ; $x<12 ; $x++){
        $GLOBALS['playersChosen'][$x] = FALSE;
    }
}

除非您需要让团队精确匹配,否则即使只覆盖了一小部分不同组合,这也可能会给您非常接近的结果,因为标准偏差和分布背后的数学。

您可以通过“经验法则”确定可接受的总分差异,并搜索直到您找到满足该条件的一个玩家组合或运行最长搜索时间,才能使该功能更加智能化(可能会生成一个警报,表示搜索超时,且比赛不均匀。)

答案 1 :(得分:1)

这在SQL中很容易做到,在数据库中执行它有一定的优势 - 值得注意的是,数据库可以利用并行性。以下是其中一个团队的6名团队成员。其余的应该很容易理解:

select t1.index, t2.index, t3.index, t4.index, t5.index, t6.index,
       (t1.score+t2.score+t3.score+t4.score+t5.score+t6.score) as TeamScore
from t t1 join
     t t2
     on t1.index < t2.index join
     t t3
     on t2.index < t3.index join
     t t4
     on t3.index < t4.index join
     t t5
     on t4.index < t5.index join
     t t6
     on t5.index < t6.index cross join
     (select cast(sum(score)/2 as integer) as score from t) as Half
where Half.Score - TeamScore in (0, 1)
order by (Half.score - TeamScore)
limit 1

答案 2 :(得分:0)

触发以下查询,它将在团队1中放置6条记录

 update table1 t1 set t1.team="1" where id IN(
    SELECT y.id
      FROM (SELECT t.id,
                   t.scores,
                   (SELECT SUM(x.scores)
                      FROM table1 x
                     WHERE x.id <= t.id) AS running_total
             FROM table1 t
         ORDER BY t.id) y
     WHERE y.running_total > (select * from (SELECT SUM(scores)/2 FROM table1) as sum) 
    ORDER BY y.id);

现在,下面的查询将在团队2中放入其他6条记录

update table1 t1 set t1.team="2" where id NOT IN(
    SELECT y.id
      FROM (SELECT t.id,
                   t.scores,
                   (SELECT SUM(x.scores)
                      FROM table1 x
                     WHERE x.id <= t.id) AS running_total
             FROM table1 t
         ORDER BY t.id) y
     WHERE y.running_total > (select * from (SELECT SUM(scores)/2 FROM table1) as sum) 
    ORDER BY y.id);