1

私は次のようなテーブルウィッチを持っています:

--------------------------------------------
| | インデックス | プレーヤー | 日付 | スコア |
--------------------------------------------
| | 1 | ヤン | 2013-01-13 | 5 |
--------------------------------------------
| | 2 | ピート | 2013-01-13 | 6 |
--------------------------------------------
| | 3 | クラース | 2013-01-13 | 5 |
--------------------------------------------
| | 4 | キース | 2013-01-13 | 7 |
--------------------------------------------
| | 5 | ウィリアム | 2013-01-13 | 8 |
--------------------------------------------
| | 6 | ジョン | 2013-01-13 | 4 |
--------------------------------------------

2013-01-14 の試合のように、次の試合を行うために、2 つのスコアを同じチームにしたいと考えています。

日付期間ごとに 12 人のプレーヤーが存在するため、2013 年 1 月 13 日には 12 人のプレーヤーであり、2013 年 1 月 14 日にはまだ同じプレーヤーがいます。

彼らは 2 つのチームに分かれなければならないので、12 / 2 = 6. 各チームに 6 人の男性がいます。それは問題ではなく、両方のチームの合計スコアが等しいか、互いに近い必要があるということです。

12 人のプレーヤーのすべてのスコアが 77 の場合、2 つのチームの合計スコアは、このようにほぼ等しくなければなりません 77 / 2 = 38,5

チーム 1 - プレーヤー 6 - 合計スコア 37

チーム 2 - プレーヤー 6 - 合計スコア 40

最終的に、クエリの出力は次のようになります。

-----------------------------------------------
| | インデックス | プレーヤー | 日付 | スコア | チーム |
-----------------------------------------------
| | 1 | ヤン | 2013-01-13 | 5 | 1 |
-----------------------------------------------
| | 2 | ピート | 2013-01-13 | 6 | 1 |
-----------------------------------------------
| | 3 | クラース | 2013-01-13 | 8 | 1 |
-----------------------------------------------
| | 4 | キース | 2013-01-13 | 7 | 1 |
-----------------------------------------------
| | 5 | ウィリアム | 2013-01-13 | 5 | 1 |
-----------------------------------------------
| | 6 | ジョン | 2013-01-13 | 6 | 1 |
-----------------------------------------------
| | 7 | ゲリット | 2013-01-13 | 6 | 2 |
-----------------------------------------------
| | 8 | マーチェ | 2013-01-13 | 6 | 2 |
-----------------------------------------------
| | 9 | しゃら | 2013-01-13 | 8 | 2 |
-----------------------------------------------
| | 10 | エルス | 2013-01-13 | 7 | 2 |
-----------------------------------------------
| | 11 | アレン | 2013-01-13 | 5 | 2 |
-----------------------------------------------
| | 12 | スティーブン | 2013-01-13 | 8 | 2 |
-----------------------------------------------

-----------------------------------------------
| | チーム | スコア | 日付 | プレーヤー |
-----------------------------------------------
| | チーム 1 | 37 | 2013-01-13 | 6 |
-----------------------------------------------
| | チーム 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でない場合、最低の結果が返されます

4

3 に答える 3

4

moonwave99 が言ったように、これを PHP で行うことは、SQL で行うよりもはるかに良い考えです。

問題は、これが解決するのが難しい問題だということです。次のように質問を再質問することで、それを確認できます。

「一方のチームに 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 つ見つかるか、最大検索時間が実行されるまで検索することで、関数をさらにスマートにすることができます (おそらく検索がタイムアウトしたことを警告し、一致が不均一です)。

于 2013-01-14T11:06:26.567 に答える
1

これは SQL では簡単に実行でき、データベースで実行すると、特定の利点があります。特に、データベースは並列処理を利用できます。以下は、チームの 1 つで 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
于 2013-01-14T14:42:55.927 に答える
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);
于 2013-01-14T12:53:20.127 に答える