我需要根据以下规则在锦标赛玩家中找到理想的配对:
它基本上是一个简化的瑞士锦标赛系统。
我有以下排名:
[{
"playerIndex": 0,
"points": 0,
"opponents": [3, 2, 4]
}, {
"playerIndex": 1,
"points": 3,
"opponents": [4, 5, 2]
}, {
"playerIndex": 2,
"points": 3,
"opponents": [5, 0, 1]
}, {
"playerIndex": 3,
"points": 4,
"opponents": [0, 4, 5]
}, {
"playerIndex": 4,
"points": 6,
"opponents": [1, 3, 0]
}, {
"playerIndex": 5,
"points": 2,
"opponents": [2, 1, 3]
}]
阅读为:第一个数组项目是玩家编号(索引)0,已经玩过玩家编号(索引)3,2和4并获得0分,每个项目为6个玩家中的一个。
我需要为第四场比赛挑选三场比赛。遵循规则,没有两个玩家可以不止一次地进行相互比赛,我选择以下比赛:
[ [ 0, 1 ], [ 0, 5 ], [ 1, 3 ], [ 2, 3 ], [ 2, 4 ], [ 4, 5 ] ]
这六个可能的比赛中的每一个都有两个球员之间的分数如下:
[3, 2, 1, 1, 2, 4]
第四轮的理想配对让每位球员在一轮比赛中获得最低分差的比赛是:
[ [0, 5], [1, 3], [2, 4] ]
有没有办法实时找到这些理想的配对?不可能尝试所有可能的组合,因为锦标赛中可能有超过100人,计算将永远。
我被建议使用https://en.wikipedia.org/wiki/Edmonds%27_algorithm或https://en.wikipedia.org/wiki/Edmonds%E2%80%93Karp_algorithm(两者都在JS中提供:https://www.npmjs.com/package/edmonds-blossom和https://github.com/sfentress/edmunds-karp)。但我不确定如何阅读结果。
有人可以帮忙吗?
答案 0 :(得分:0)
编辑:如果有太多可能的解决方案,匈牙利的alghoritm会失败。在我的情况下,在第一轮比赛之后,有很多球员得分相同。
Edmond Blossoms alghoritm的表现要好得多(通过NPM发现这个JS实现https://github.com/mattkrick/EdmondsBlossom)。
无法理解如何使用它。主要区别在于您需要使用成对进给它,并且对于应该优先选择的对,对之间的点差异更大。所以我对以前玩过的对使用零差异。
我的最终(希望)解决方案:
var maxDiff = (roundIndex + 1) * this.config.pointsWin
var possiblePairs = []
availablePlayers.forEach(player => {
availablePlayers.forEach(opponent => {
if (
player.playerIndex !== opponent.playerIndex // &&
// player.opponents.indexOf(opponent.playerIndex) === -1
) {
var match = [player.playerIndex, opponent.playerIndex]
match.sort(function(a, b) {
return a - b;
})
if (player.opponents.indexOf(opponent.playerIndex) === -1) {
match.push(maxDiff - Math.abs(player.points - opponent.points))
}
else {
match.push(0)
}
if (this.searchForArray(possiblePairs, match) === -1) {
possiblePairs.push(match)
}
}
})
})
var rawPairing = edmondsBlossom(possiblePairs)
rawPairing.forEach((match, index) => {
if (match !== -1 && match < index) {
round.matches.push({
home: match,
home_score: '',
away: index,
away_score: '',
referee: -1
})
}
})
首先,我计算玩家之间的最大可能分数差异(期望有人可以获得零分,而其他人则全部获得)。然后在玩家之间创建所有可能的组合,并使用MAX POSSIBLE POINTS - PLAYERS POINTS DIFFERENCE或ZERO为之前匹配的玩家标记它们。
然后将数组提供给EdmondsBlossom函数,该函数返回整数数组... [6,8,14,5,15,3,0,10,1,12,7,13,9,11,2,4] ...阅读如下:球员指数0应该与球员6,球员1对8,球员2对14,球员3对5 ...球员5对3(重复)配对。有时在输出中有-1值,只是跳过。
这是我的解决方案(已删除):
感谢@ VedPrakash的评论,我找到了解决我问题的匈牙利算法。幸运的是,NPM上还有一个JS实现https://github.com/addaleax/munkres-js。
Munkers功能需要一个矩阵作为输入。在我的情况下,我的矩阵的交叉点上的玩家点差异(见下文)。已经相互比赛的对具有更高的价值,无法实现(在我的情况下为9)。
输入矩阵:
[ [ 9, 4, 9, 9, 9, 3 ],
[ 4, 9, 9, 2, 9, 9 ],
[ 9, 9, 9, 2, 4, 9 ],
[ 9, 2, 2, 9, 9, 9 ],
[ 9, 9, 4, 9, 9, 5 ],
[ 3, 9, 9, 9, 5, 9 ] ]
输出:
[ [ 0, 5 ], [ 1, 3 ], [ 2, 4 ], [ 3, 1 ], [ 4, 2 ], [ 5, 0 ] ]
要注意的最后一件事是过滤Munkers输出(包含重复项 - 两对0vs1和1vs0),所以我只需通过比较第一和第二索引来过滤它们。
我的实施:
var maxDiff = (roundIndex + 1) * this.config.pointsWin
// prepare matrix
var matrix = [];
for (var i = 0; i < availablePlayers.length; i++) {
matrix[i] = new Array(availablePlayers.length);
matrix[i].fill(0)
}
// fill matrix with players points diff
for (var y = 0; y < availablePlayers.length; y++) {
var playerY = availablePlayers[y]
for (var x = 0; x < availablePlayers.length; x++) {
var playerX = availablePlayers[x]
if (x === y) {
matrix[x][y] = maxDiff
}
else if (playerY.opponents.indexOf(x) !== -1) {
matrix[x][y] = maxDiff
matrix[y][x] = maxDiff
}
else {
var value = Math.abs(playerX.points - playerY.points)
matrix[x][y] = value
matrix[y][x] = value
}
}
}
// console.table(matrix)
// console.table(computeMunkres(matrix))
// return
// make pairing
var rawPairing = computeMunkres(matrix)
rawPairing.forEach(pairing => {
if (pairing[0] < pairing[1]) {
round.matches.push({
home: pairing[0],
home_score: '',
away: pairing[1],
away_score: '',
referee: -1
})
}
})