我有以下阵列的球员和他们的积分。我想把它们分成两个相等的小组,其中点的总和应尽可能相等。
E.g输出应为:
团队a =玩家ID为505,481,510,总分为6
球队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
)
)
答案 0 :(得分: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
)
)
更新其实我在开玩笑,8位玩家需要11秒,9位玩家需要1分钟,10位玩家需要10分钟。)