我有一个从此代码生成的对的列表
int n = listTeam.size();
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (i != j)
listTeamPairs.add(new Team[] { listTeam.get(i), listTeam.get(j) });
}
}
}
如果有6支队伍,这将正确生成这些对。
[0 1 , 0 2 , 0 3 , 0 4 , 0 5 , 1 2 , 1 3 , 1 4 , 1 5 , 2 3 , 2 4 , 2 5 , 3 4 , 3 5 , 4 5 ]
我遇到的问题是将这些对选择为相同大小的圆(桶)(在这种情况下为三个)。
第一轮将成为
0-1, 2-3, 4-5
问题出现在第二轮
0-2, 1-3 <- swap order of these matches.
This leaves only team 4-5 again. Which is not valid.
生成轮次而没有无效条目但不是完整存储桶的代码
private boolean generateRound(Team[] teamInRound, List<Team[]> roundTeams) {
Team team1 = teamInRound[0];
Team team2 = teamInRound[1];
Optional<Team[]> t = roundTeams.stream().filter(p -> p[0].getName().contentEquals(team1.getName()) ||
p[1].getName().contentEquals(team2.getName()) || p[0].getName().contentEquals(team2.getName()) ||
p[1].getName().contentEquals(team1.getName())).findAny();
if (t.isPresent())
return false;
roundTeams.add(teamInRound);
tmpTeamPairs.remove(teamInRound);
return true;
}
private void generateRounds(List<Team[]> teams) {
for (int i = 0; i < listTeam.size() / 2;i++) {
System.out.println("Reamining pairs");
tmpTeamPairs.stream().forEach(p -> System.out.println(p[0].getName() + " - " + p[1].getName()));
if (i == 0) {
teams.add(tmpTeamPairs.get(0));
tmpTeamPairs.remove(0);
continue;
}
for (Team[] pair : tmpTeamPairs) {
boolean b = generateRound(pair, teams);
if (b) {
break;
}
}
}
}
看看提议的答案,似乎并没有生成所需的桶。
scheduled team 0 against team 4
scheduled team 2 against team 3 <-----
scheduled team 5 against team 1
Array order
0
2 <---
5
4
3 <---
1
Lag 5 - Lag3
Lag1 - Lag2 <-----
Lag4 - Lag 6
-----------------------------------------------
scheduled team 0 against team 5
scheduled team 1 against team 4
scheduled team 2 against team 3 <----
Array order
0
1
2 <---
5
4
3 <---
Lag 5 - Lag4
Lag 6 - Lag3
Lag1 - Lag2 <-----
答案 0 :(得分:2)
你想要达到的目标是制作锦标赛计划。这可以使用循环调度算法Round robin scheduling
来完成这可以通过固定其中一个竞争对手来实现,假设为0.其余的将顺时针旋转以产生新的组合。
实现此目的的代码可能如下所示:
public static void generateRoundRobinPairs(List<Integer> teams) {
Integer fixedElement = teams.get(0);
List<Integer> teamsWithoutFirst = teams.subList(1,teams.size());
for (int i = 0; i < teamsWithoutFirst.size(); i++) {
List<Integer> toSchedule = new ArrayList<>();
toSchedule.add(fixedElement);
teamsWithoutFirst = buildNewRotation(teamsWithoutFirst);
toSchedule.addAll(teamsWithoutFirst);
scheduleRound(toSchedule);
}
}
public static void scheduleRound(List<Integer> teams) {
for (int i = 0; i < teams.size() / 2; i++) {
// here create your data structure
String template ="scheduled team %s against team %s";
System.out.println(String.format(template, teams.get(i), teams.get(i + teams.size() / 2)));
}
}
public static List<Integer> buildNewRotation(List<Integer> l) {
List<Integer> newList = new ArrayList<>();
newList.add(l.get(l.size() / 2));
for (int i = 0; i < l.size() / 2 - 1; i++) {
newList.add(l.get(i));
}
for (int i = 0; i < l.size() / 2; i++) {
newList.add(l.get(i + 1 + l.size() / 2));
}
newList.add(l.get(l.size() / 2 - 1));
return newList;
}
答案 1 :(得分:2)
这是循环计划的另一个实现。
它返回一对桶的列表。虽然您可以创建自定义类,但是只使用List
实现了对。
每个存储桶都是Set
,因为只要团队配对已知,存储桶中的订单就无关紧要了。
计划本身是List
,因为订单在计划中很重要。
该方法是通用的,因此您可以将这些小组放在Integer
或String
中,看看它是否运作正常,或使用完整的Team
类。
public static <T> List<Set<List<T>>> roundRobin(List<T> teams) {
int numTeams = teams.size();
// For a proper league, we only allow even number of teams.
if ( numTeams % 2 != 0 ) {
throw new IllegalArgumentException("Number of teams not even " + numTeams);
}
List<Set<List<T>>> result = new ArrayList<>(numTeams - 1);
// Implement the round robin by rotating the right side of the list
// every time, then pairing opposite teams. Note that the first
// item is not part of the rotation.
for ( int i = 0; i < numTeams - 1; i++ ) {
Collections.rotate(teams.subList(1,numTeams), 1);
Set<List<T>> bucket = new HashSet<>();
for ( int j = 0; j < numTeams / 2; j++ ) {
bucket.add(Arrays.asList(teams.get(j), teams.get(numTeams - j - 1)));
}
result.add(bucket);
}
return result;
}
这里的“技巧”是在Collections.rotate
结果上使用subList()
。这意味着旋转实际上反映在原始列表中,因此我们最终会得到一个包含冻结团队的完整列表,这样可以更容易地循环使用。
首先匹配最后一对,倒数第二匹配等等。
使用此main
:
List<String> teams = Arrays.asList(
"Manchester Utd.",
"Chelsea",
"Tottenham",
"Liverpool",
"Arsenal",
"West Ham Utd." );
for ( Set<List<String>> bucket : roundRobin(teams)) {
for ( List<String> pair : bucket) {
System.out.println(pair);
}
System.out.println();
}
结果:
[West Ham Utd., Liverpool] [Chelsea, Tottenham] [Manchester Utd., Arsenal] [Manchester Utd., Liverpool] [Arsenal, Tottenham] [West Ham Utd., Chelsea] [Liverpool, Chelsea] [Manchester Utd., Tottenham] [Arsenal, West Ham Utd.] [Liverpool, Arsenal] [Tottenham, West Ham Utd.] [Manchester Utd., Chelsea] [Manchester Utd., West Ham Utd.] [Tottenham, Liverpool] [Chelsea, Arsenal]
请注意,在真实的体育赛事中,赛程表还反映了谁在主场比赛以及谁在比赛中出场。在这里,冷冻团队可以在家里玩所有游戏,至少在第一轮比赛中。如果您需要公平的家庭安排,您可以更改行:
bucket.add(Arrays.asList(teams.get(j), teams.get(numTeams - j - 1)));
为:
Set<List<T>> pair = Arrays.asList(teams.get(j), teams.get(numTeams - j - 1));
if ( i % 2 == 1 && j == 0 ) {
Collections.reverse(pair);
}
bucket.add(pair);