我无法想出解决方案,因此我想寻求帮助。我有一份名单:
var listNames = ['John', 'William', 'James', 'George', 'Charles',
'Frank', 'Joseph', 'Henry', 'Robert', 'Thomas',
'Edward', 'Harry', 'Walter', 'Arthur'];
我希望通过单击一个按钮在它们之间生成一些随机耦合,而不重复已经耦合的名称。示例:
John-James,William-George,Charles-Joseph,Frank-Henry,Robert-Edward,Thomas-Harry,Walter-Arthur
生成此列表后,我想生成其他列表n次,直到所有名称匹配在一起。我想做的一个例子是在这个网站上:https://www.blia.it/utili/campionato/。通过在列中添加名称,它可以生成团队配对的日历,并且不会重复同一配对超过2次。
如何在JavaScript和Java中执行此操作?感谢任何能帮助我的人。
我不懂数学,但实验表明,只有4、8、16、32个团队等产生了可能的解决方案。
根据您的评论,此编辑允许连续进行主客场比赛。我没有具体尝试,但这种尝试似乎已经产生了一个相当公平的解决方案。
如果你在下半赛季复制解决方案,并更换每对搭档,每支球队将获得完全相同数量的主客场比赛。
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Season {
private static final int NUMBER_OF_TEAMS = 8 /* 4, 8, 16, 32, 64... */;
private static class Day {
private int index = -1;
private List<Pairing> pairings = new ArrayList<>();
@Override
public String toString() {
return String.format("Day %2d: %s", index + 1, pairings);
}
}
private static class Pairing {
private int a;
private int b;
@Override
public String toString() {
return String.format("%2d-%2d", a + 1, b + 1);
}
}
public static void main(String[] args) throws Exception {
List<Integer> teams = IntStream.range(0, NUMBER_OF_TEAMS).mapToObj(i -> Integer.valueOf(i)).collect(Collectors.toList());
List<Pairing> pairings = createPairings(teams);
System.out.println("all pairings: " + pairings);
List<Day> days = createMatchDays(teams, pairings);
System.out.println();
System.out.println("match days first half of season (systematic):");
days.forEach(i -> System.out.println(i));
alternateHomeAndAwayGames(days);
}
private static List<Pairing> createPairings(List<Integer> teams) {
// "n choose 2", or C(n,2)
List<Pairing> pairings = new ArrayList<>();
for(int a = 0; a < teams.size(); a++) {
for(int b = a + 1; b < teams.size(); b++) {
Pairing pairing = new Pairing();
pairing.a = teams.get(a);
pairing.b = teams.get(b);
pairings.add(pairing);
}
}
return pairings;
}
private static List<Day> createMatchDays(List<Integer> teams, List<Pairing> pairings) {
int numberOfMatchDays = teams.size() - 1;
int pairingsPerMatchDay = teams.size() / 2;
List<Pairing> remainingPairings = new ArrayList<>(pairings);
List<Day> days = new ArrayList<>();
for(int dayIndex = 0; dayIndex < numberOfMatchDays; dayIndex++) {
Day day = new Day();
days.add(day);
day.index = dayIndex;
Set<Integer> teamsAlreadyPlaying = new HashSet<>();
for(int i = 0; i < pairingsPerMatchDay; i++) {
Pairing pairing = findPairing(remainingPairings, teamsAlreadyPlaying);
day.pairings.add(pairing);
}
}
return days;
}
private static Pairing findPairing(List<Pairing> remainingPairings, Set<Integer> teamsAlreadyPlaying) {
for(Pairing candidate : remainingPairings) {
if(!teamsAlreadyPlaying.contains(candidate.a) && !teamsAlreadyPlaying.contains(candidate.b)) {
teamsAlreadyPlaying.add(candidate.a);
teamsAlreadyPlaying.add(candidate.b);
remainingPairings.remove(candidate);
return candidate;
}
}
throw new IllegalStateException("failed to find pairing");
}
private static void alternateHomeAndAwayGames(List<Day> days) {
System.out.println();
System.out.println("trying to alternate home and away games as much as possible...");
int[] repeatHome = new int[NUMBER_OF_TEAMS];
int[] repeatAway = new int[NUMBER_OF_TEAMS];
for(int dayIndex = 1; dayIndex < days.size(); dayIndex++) {
Day prevDay = days.get(dayIndex - 1);
Day nextDay = days.get(dayIndex);
System.out.println("fitting day " + (dayIndex + 1));
// mark for each team if it played home or away during last day
boolean[] playedHome = new boolean[NUMBER_OF_TEAMS];
boolean[] playedAway = new boolean[NUMBER_OF_TEAMS];
for(Pairing pairing : prevDay.pairings) {
playedHome[pairing.a] = true;
playedAway[pairing.b] = true;
}
// try to switch pairings of candidate, so that no team has to play home or away twice in a row
for(int pairIndex = 0; pairIndex < nextDay.pairings.size(); pairIndex++) {
Pairing pairing = nextDay.pairings.get(pairIndex);
if(playedHome[pairing.a] && playedAway[pairing.b]) {
switchTeamsInPairing(pairing);
}
if(!playedHome[pairing.a] && !playedAway[pairing.b]) {
// ok
playedHome[pairing.a] = true;
playedAway[pairing.b] = true;
continue;
}
// first try a-b
if(pairing.a > pairing.b) {
switchTeamsInPairing(pairing);
}
if(playedHome[pairing.a]) {
repeatHome[pairing.a]++;
System.out.println(String.format("%s Pair %2d repeat team %2d: home+ %s away %s", nextDay, pairIndex + 1, pairing.a + 1,
repeatHome[pairing.a], repeatAway[pairing.a]));
continue;
}
if(playedAway[pairing.b]) {
repeatAway[pairing.b]++;
System.out.println(String.format("%s Pair %2d repeat team %2d: home %s away+ %s", nextDay, pairIndex + 1, pairing.b + 1,
repeatHome[pairing.b], repeatAway[pairing.b]));
continue;
}
// then try b-a
switchTeamsInPairing(pairing);
if(playedHome[pairing.a]) {
repeatHome[pairing.a]++;
System.out.println(String.format("%s Pair %2d repeat team %2d: home+ %s away %s", nextDay, pairIndex + 1, pairing.a + 1,
repeatHome[pairing.a], repeatAway[pairing.a]));
continue;
}
if(playedAway[pairing.b]) {
repeatAway[pairing.b]++;
System.out.println(String.format("%s Pair %2d repeat team %2d: home %s away+ %s", nextDay, pairIndex + 1, pairing.b + 1,
repeatHome[pairing.b], repeatAway[pairing.b]));
continue;
}
}
}
System.out.println();
System.out.println("match days first half of season (shuffled):");
days.forEach(i -> System.out.println(i));
// count home/away
int[] home = new int[NUMBER_OF_TEAMS];
int[] away = new int[NUMBER_OF_TEAMS];
for(Day day : days) {
for(Pairing pairing : day.pairings) {
home[pairing.a]++;
away[pairing.b]++;
}
}
System.out.println("statistics");
for(int i = 0; i < NUMBER_OF_TEAMS; i++) {
System.out.println(String.format("Team %2d: home/away: %2d/%2d home/away-repeats: %2d/%2d", i + 1, home[i], away[i], repeatHome[i],
repeatAway[i]));
}
}
private static void switchTeamsInPairing(Pairing pairing) {
int tmp = pairing.a;
pairing.a = pairing.b;
pairing.b = tmp;
}
}
8个团队的输出:
all pairings: [ 1- 2, 1- 3, 1- 4, 1- 5, 1- 6, 1- 7, 1- 8, 2- 3, 2- 4, 2- 5, 2- 6, 2- 7, 2- 8, 3- 4, 3- 5, 3- 6, 3- 7, 3- 8, 4- 5, 4- 6, 4- 7, 4- 8, 5- 6, 5- 7, 5- 8, 6- 7, 6- 8, 7- 8]
match days first half of season (systematic):
Day 1: [ 1- 2, 3- 4, 5- 6, 7- 8]
Day 2: [ 1- 3, 2- 4, 5- 7, 6- 8]
Day 3: [ 1- 4, 2- 3, 5- 8, 6- 7]
Day 4: [ 1- 5, 2- 6, 3- 7, 4- 8]
Day 5: [ 1- 6, 2- 5, 3- 8, 4- 7]
Day 6: [ 1- 7, 2- 8, 3- 5, 4- 6]
Day 7: [ 1- 8, 2- 7, 3- 6, 4- 5]
trying to alternate home and away games as much as possible...
fitting day 2
Day 2: [ 1- 3, 2- 4, 5- 7, 6- 8] Pair 1 repeat team 1: home+ 1 away 0
Day 2: [ 1- 3, 2- 4, 5- 7, 6- 8] Pair 2 repeat team 4: home 0 away+ 1
Day 2: [ 1- 3, 2- 4, 5- 7, 6- 8] Pair 3 repeat team 5: home+ 1 away 0
Day 2: [ 1- 3, 2- 4, 5- 7, 6- 8] Pair 4 repeat team 8: home 0 away+ 1
fitting day 3
fitting day 4
Day 4: [ 1- 5, 2- 6, 3- 7, 4- 8] Pair 1 repeat team 5: home 1 away+ 1
Day 4: [ 1- 5, 2- 6, 3- 7, 4- 8] Pair 2 repeat team 6: home 0 away+ 1
Day 4: [ 1- 5, 2- 6, 3- 7, 4- 8] Pair 3 repeat team 3: home+ 1 away 0
Day 4: [ 1- 5, 2- 6, 3- 7, 4- 8] Pair 4 repeat team 4: home+ 1 away 1
fitting day 5
fitting day 6
fitting day 7
match days first half of season (shuffled):
Day 1: [ 1- 2, 3- 4, 5- 6, 7- 8]
Day 2: [ 1- 3, 2- 4, 5- 7, 6- 8]
Day 3: [ 4- 1, 3- 2, 8- 5, 7- 6]
Day 4: [ 1- 5, 2- 6, 3- 7, 4- 8]
Day 5: [ 6- 1, 5- 2, 8- 3, 7- 4]
Day 6: [ 1- 7, 2- 8, 3- 5, 4- 6]
Day 7: [ 8- 1, 7- 2, 6- 3, 5- 4]
statistics
Team 1: home/away: 4/ 3 home/away-repeats: 1/ 0
Team 2: home/away: 3/ 4 home/away-repeats: 0/ 0
Team 3: home/away: 4/ 3 home/away-repeats: 1/ 0
Team 4: home/away: 3/ 4 home/away-repeats: 1/ 1
Team 5: home/away: 4/ 3 home/away-repeats: 1/ 1
Team 6: home/away: 3/ 4 home/away-repeats: 0/ 1
Team 7: home/away: 4/ 3 home/away-repeats: 0/ 0
Team 8: home/away: 3/ 4 home/away-repeats: 0/ 1
为了生成不重复的配对,可以使用随机索引并将元素从数组中弹出,这样它们就不会重复。
对于问题的第二部分,我会为每个配对创建一个带有密钥条目的对象,并在每次抽奖后检查密钥是否不存在。
这是这个问题的蓝图。https://codesandbox.io/s/heuristic-grothendieck-vkt6f?file=/src/index.js