我遇到了问题,正在尝试开发或使用算法来解决此问题。
我有8个玩家,每个玩家可以与其他玩家组成7个独特的团队。一队由2名球员组成。
这里是一个例子, 可以说所有玩家的名字都是
[A,B,C,D,E,F,G,H]
现在,从这8名球员中,我可以创建总共28
个独特的团队组合。
现在我要进行7轮比赛,每轮比赛他们都必须与独特的球队一起比赛。
我尝试了round robin algorithm
,但是它可以工作4个回合。无法创建7个回合。
A B C D
E F G H
ROUND 1: AE, BF, CG, DH
E A B C
F G H D
ROUND 2: EF, AG, BH, CD
F E A B
G H D C
ROUND 3: FG, EH, AD, BC,
G F E A
H D C B
ROUND 4: GH, FD, EC, AB
我仍然需要使用一组独特的球员组合再进行3回合。
任何帮助将不胜感激。谢谢。
答案 0 :(得分:1)
为保持最大多样性,切勿将每个玩家与之前配对过的玩家配对。由于有8个玩家和7个回合,这意味着每个玩家将需要与对方完全匹配一次。每轮有4对。
由于有8个玩家,我们可以将每个玩家表示为一个字节。
Enum PlayerId : Byte {
PLAYER_A = 1,
PLAYER_B = 2,
PLAYER_C = 4,
PLAYER_D = 8,
PLAYER_E = 16,
PLAYER_F = 32,
PLAYER_G = 64,
PLAYER_H = 128
}
// player index to player id lookup
PlayerId _playerIds[] = { PLAYER_A, PLAYER_B, PLAYER_C, ... }
对于每个单独的玩家,有7个独特的配对,所有配对都将在游戏中显示。对于每个回合,我们需要4个这样的配对而没有冲突:即,所有玩家在所有此类配对中必须恰好一次。
我们将使用图形来表示所有可能性。我们将为每个可能的配对创建一个节点,并在彼此兼容的节点之间创建边缘(即,玩家选择中没有冲突)。
public class PairingGraph {
Map<Byte, PairingNode*> nodes = new Map<Byte, PairingNode*>();
Map<Byte, PairingEdge*> edges = new Map<Byte, PairingEdge*>();
PairingNode* AddPairing(Player p1, Player p2) {
PairingNode n(this, p1, p2);
if(nodes.ContainsKey(n->id)) {
throw new Exception("Duplicate Player Pairing");
nodes[n->id] = n;
for other : nodes {
if(n->id & other->id) continue;
edges->Add(new PairingEdge(this, n, other));
}
return n;
}
boolean RemoveNode(Byte id) {
if (!nodes.ContainsKey(id)) return false;
auto n = nodes[id];
// first remove any edges that this node is part of.
for e : n->edges {
if (e->p1 != n) {
e->p1->edges.remove(e);
} else {
e->p2->edges.remove(e);
}
delete e;
}
nodes.remove(n);
delete n;
return true;
}
PairingGraph() {
// initialize the graph with all player combinations
for(int i = 0; i < 8; i++) {
for(int j = i + 1; j < 8; j++) {
AddPairing(_playerIds[i], _playerIds[j]);
}
}
}
}
public class PairingNode {
PairingGraph* graph;
List<PairingEdge> edges;
PlayerId p1;
PlayerId p2;
Byte id;
PairingNode(PairingGraph* g, PlayerId p1, PlayerId p2) {
if(p1 == p2) throw new Exception("Two distinct players are required to create a PairingNode");
this.graph = g;
this.p1 = p1;
this.p2 = p2;
this.id = p1 | p2;
}
}
public class PairingEdge {
PairingGraph* g;
PairingNode* p1;
PairingNode* p2;
Byte id;
PairingEdge(PairingGraph* g, PairingNode* p1, PairingNode* p2) {
if(p1->id & p2->id) throw new Exception("Cannot create edges between PairingNode's that share a player");
this.graph = g;
this.p1 = p1;
this.p2 = p2;
this.id = p1->id | p2->id;
this.p1.edges.Add(this);
this.p2.edges.Add(this);
}
}
现在我们可以使用所有可能的组合构造一个PairingGraph,我们用于创建配对的算法很简单:从图中随机选择和删除节点,并附加了一个约束,即删除的节点不会与该回合中以前选择的任何节点冲突
List<Tuple<PlayerId, PlayerId>>* SelectPlayersForRound(PairingGraph* g) {
List<Tuple<PlayerId, PlayerId>> results = new List<Tuple<PlayerId, PlayerId>>;
Byte restrictions = 0;
// start by randomly selecting an intial node.
int selection = rand(0, g->nodes->count -1);
auto last_node = g->nodes[g->nodes->keys(selection)];
restrictions |= n->id;
selectedNodes.Add(n);
// select the three other player pairs, informed from previous selections.
for(int i = 1; i < 4; i++)
{
// start by randomly selecting an edge from the last node
// it necessarily won't conflict with the last_node, but may
// not meet all restriction criteria
int selection = rand(0, last_node->edges->count -1);
// Grab the node on the opposite end of the selected edge
auto e = last_node->edges[selection];
auto next_node = (e->p1 == last_node)? e->p2 : e->p1;
// If the node doesn't meet our current restrictions, try again.
while(next_node->id & restrictions) {
selection++;
if(selection == last_node->edges->count) selection++;
e = last_node->edges[selection];
next_node = (e->p1 == last_node)? e->p2 : e->p1;
}
// Remove the last_node from the Graph
g->RemoveNode(last_node->id);
// update for next iteration
last_node = curr_node;
restrictions |= last_node->id;
}
// Remove the last_node from the Graph
g->RemoveNode(last_node->id);
return results;
}
只需为每个游戏创建一个新的PairingGraph,然后在每个回合中调用SelectPlayersForRound,就可以完成!
请注意,这只是一些伪代码(因为您未指定语言),并且未经测试。希望对您有所帮助:)
编辑:您已在帖子中添加了一些语言。我的伪代码或多或少是c ++,因此您应该可以轻松地出于自己的目的进行复制-修改。
EDIT2:改进了选择例程,以利用last_node的兼容边列表(减少潜在冲突的次数)
EDIT3:修复了一些条件逻辑,其中我不正确地使用^而不是&