将PHP数组拆分为两个相等的集合,其中值的总和相等


Split PHP array into two equal sets where the sum of value are equal

我有下面的球员数组和他们的分数。我想把他们分成两个相等的小组,尽可能使总得分相等。

E。G输出应为:

team a =球员id的505,481,510,总分为6

team b =球员id的504,509,513,总分为6

你能帮我指出正确的方向如何实现这一点吗?

谢谢

Array
(
    [0] => Array
        (
            [match_id] => 664
            [0] => 664
            [player_id] => 505
            [1] => 505
            [Points] => 4
            [2] => 4
        )
    [1] => Array
        (
            [match_id] => 664
            [0] => 664
            [player_id] => 481
            [1] => 481
            [Points] => 1
            [2] => 1
        )
    [2] => Array
        (
            [match_id] => 664
            [0] => 664
            [player_id] => 510
            [1] => 510
            [Points] => 1
            [2] => 1
        )
    [3] => Array
        (
            [match_id] => 664
            [0] => 664
            [player_id] => 504
            [1] => 504
            [Points] => 1
            [2] => 1
        )
    [4] => Array
        (
            [match_id] => 664
            [0] => 664
            [player_id] => 509
            [1] => 509
            [Points] => 4
            [2] => 4
        )
    [5] => Array
        (
            [match_id] => 664
            [0] => 664
            [player_id] => 513
            [1] => 513
            [Points] => 1
            [2] => 1
        )
)

所以这个问题是一个分区优化问题,猜猜看,它是np完全的!因此,您应该真正指定是需要最佳结果还是可接受的结果,因为它在算法和计算时间方面有很大的不同。如果你有一个非常小的数据集,最好的结果可以很快计算出来,但如果你的团队很大,这可能是一个真正的痛苦。

今天我感觉很精确(加上我不喜欢模糊和启发式lol),所以我给你一个算法来计算最佳分割。它遍历所有可能的团队组合,并为每个团队计算权重(点数)差异,返回可能差异最小的团队。

你可以改进这个算法,如果他找到一个零(最好的分裂),或者只枚举组合而不是排列,但是渐近复杂性是一样的,所以我就不麻烦了。

享受
class SplitTeams {
  private $_split_weight;
  private $_split_teams;
  private $_players;
  public function __construct($players) {
    $this->_players = array();
    foreach ($players as $p) {
      $this->_players[$p['player_id']] = $p;
    }
  }
  public function getTeams() {
    $this->_list_permutations(array_keys($this->_players), array());
    $half = (int) (count($this->_split_teams) / 2);
    $team_a = array_slice($this->_split_teams, 0, $half);
    $team_b = array_slice($this->_split_teams, $half);
    return array($team_a, $team_b);
  }
  private function _calculate_diff($list) {
    $sum_team_a = 0;
    $sum_team_b = 0;
    for ($i = 0; $i < count($list); $i++) {
      if ($i < (count($list) / 2))
        $sum_team_a += $this->_players[$list[$i]]['Points'];
      else
        $sum_team_b += $this->_players[$list[$i]]['Points'];
    }
    return abs($sum_team_a - $sum_team_b);
  }
  private function _list_permutations($list, $perm) {
    if (count($list) == 0) {
      /* calculate the weight for this split */
      $w = $this->_calculate_diff($perm);
      if (($this->_split_weight === null) ||
          ($this->_split_weight > $w)) {
        /* this is a candidate solution */
        $this->_split_weight = $w;
        $this->_split_teams = $perm;
      }
      print "PERM: " . implode("; ", $perm) . " - weight $w'n";
      return;
    }
    for ($i = 0; $i < count($list); $i++) {
      // slice array
      $sublist = $list;
      $a = array_splice($sublist, $i, 1);
      $this->_list_permutations($sublist, array_merge($perm, $a));
    }
  }
}
$Data = array(
  array('player_id' => 505, 'Points' => 4),
  array('player_id' => 481, 'Points' => 1),
  array('player_id' => 509, 'Points' => 3),
  array('player_id' => 510, 'Points' => 1),
  array('player_id' => 504, 'Points' => 1),
  array('player_id' => 513, 'Points' => 2));
$s = new SplitTeams($Data);
$teams = $s->getTeams();
print_r($teams);
输出:

Array
(
    [0] => Array
        (
            [0] => 505
            [1] => 481
            [2] => 510
        )
    [1] => Array
        (
            [0] => 509
            [1] => 504
            [2] => 513
        )
)

UPDATE实际上我是开玩笑的,这个算法需要11秒8个玩家,1分钟9个玩家,10分钟10个玩家:)