Vollständigesturnier: Lösungsalgorithmus bzw. mindestens eine Lösung für folgendes Problem gesucht

Neue Frage »

Auf diesen Beitrag antworten »
grohfuda Vollständigesturnier: Lösungsalgorithmus bzw. mindestens eine Lösung für folgendes Problem gesucht

Liebe Forumsteilnehmer, ich bin auf der Suche nach einem Lösungsalgorythmus oder wenigstens einer einzelnen Lösung für ein vollständiges Turnier. Auch wenn ich die Lösung eigentlich für etwas anderes brauche (Brettspielanalyse), möchte ich das Problem an einem anschaulichen Bespiel erläutern:


Nehmen wir einmal an 12 Hasen wollen über den Frühling bis Sommer ein vollständiges Wettlauf-Turnier mit Wellläufen gegeneinander bestreiten. Mangels Platz können immer nur 4 Hasen gleichzeitig rennen. Also wird im Laufe des Sommers jeder Hase mit allen Kombinationen von jeweils 3 anderen Hasen ein Rennen absolvieren:

H1, H2, H3, H4
H1, H2, H3, H5
H1, H2, H3, H6
[...]
H9, H10, H11, H12


Die Anzahl der möglichen Kombinationen beträgt 12! / (8! x 4!) = 495 (bzw. 135 pro Hase)

Nun sollen aber folgende Randbedingungen an das Turnier erfüllt sein:

1) Es sollen niemals die selben 4 Hasen ein zweites mal gegeneinander Laufen (2 bzw. 3 Hasen sind kein Problem), das heißtz.B. das Rennen H1, H2, H3, H4 darf es nur einmal geben.

2) Es werden jeden Tag genau 3 Rennen gestartet, wobei jeder Hase genau ein Rennen pro Tag absolviert. (Hierbei ist es egal in welchem der Tagesrennen jeder Hase jewils startet, auch die Bahnnummer ist nicht von Bedeutung.

Frage 1)
Wie kann hier eine Lösung aussehen? Ich vermute mal, dass das Ganze mit Backtracking lösbar ist (falls es eine Lösung gibt), leider reichen hier meine Programmierfähigkeiten nicht aus...

Randbemerkung: Für 8 Hasen und 2 Rennen ist die Lösung trivial. Man nehme ein beliebiges Hasenrennen und die übrigen Hasen laufen im zweiten. Dieser Ansatz hat mich aber hier nicht weitergebracht.


Frage 2)
Existiert eine solche Lösung auch für 16 Hasen und 4 Rennen mit 4 Hasen bzw. 15 Hasen und 3 Rennen mit 5 Hasen?


Viele Dank im Voraus.
grohfuda
 
Auf diesen Beitrag antworten »
eulerscheZahl

Letztendlich läuft das auf ein Independent Set Problem hinaus, wobei die Kanten unmögliche Paarungen sind, also solche mit doppelten Rennen.

Mein Programm schafft das und 8 Hasen und 2 Rennen in Sekundenbruchteilen, aber bei 12 und 3 habe ich es abgebrochen. Die Erkennung einer ungültigen Paarung kann man mit einer Lookup Table beschleunigen, aber ich glaube nicht, dass das reicht.
code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
using System;
using System.Linq;
using System.Collections.Generic;

class Infoboard
{
	public static void Main (string[] args)
	{
		int bunnies = 12; //8
		int races = 3; //2
		int participants = bunnies / races;

		List<Race> raceList = Race.CreateRaces(participants, bunnies);
		List<Day> days = Day.CreateMatchdays (raceList, races);
		List<Tournament> tournaments = Tournament.CreateTournament (days, 495 / races); //495 = binom(12, 4)
	}

	class Race {
		public int[] Participants { get; private set; }

		public Race(int[] participants) {
			this.Participants = (int[]) participants.Clone();
		}

		public bool Collide(Race r) {
			foreach (int p in this.Participants) {
				foreach (int q in r.Participants) {
					if (p == q)
						return true;
				}
			}
			return false;
		}

		public static List<Race> CreateRaces(int participants, int bunnies) {
			List<Race> matches = new List<Race> ();
			CreateRaces (matches, new int[participants], 0, 0, bunnies);
			return matches;
		}

		private static void CreateRaces(List<Race> matches, int[] current, int index, int taken, int max) {
			if (taken == current.Length) {
				matches.Add (new Race (current));
				return;
			}
			if (index >= max)
				return;
			CreateRaces (matches, current, index + 1, taken, max);
			current [taken] = index;
			CreateRaces (matches, current, index + 1, taken + 1, max);
		}

		public override string ToString ()
		{
			return string.Join (" ", Participants.Select (p => p + 1));
		}
	}

	class Day {
		public Race[] Races { get; private set; }
		public Day(Race[] races) {
			this.Races = (Race[]) races.Clone();
		}

		public static List<Day> CreateMatchdays(List<Race> raceList, int racesPerDay) {
			List<Day> days = new List<Day>();
			CreateMatchdays (days, raceList, new Race[racesPerDay], 0, 0);
			return days;
		}

		private static void CreateMatchdays(List<Day> days, List<Race> matches, Race[] current, int index, int taken) {
			if (taken == current.Length) {
				days.Add (new Day (current));
				return;
			}
			if (index >= matches.Count)
				return;
			CreateMatchdays (days, matches, current, index + 1, taken);
			if (!current.Take (taken).Any (c => c.Collide (matches [index]))) {
				current [taken] = matches [index];
				CreateMatchdays (days, matches, current, index + 1, taken + 1);
			}
		}

		public bool Collide(Day d) {
			foreach (Race p in this.Races) {
				foreach (Race q in d.Races) {
					if (p == q)
						return true;
				}
			}
			return false;
		}

		public override string ToString ()
		{
			return string.Join<Race> ("     ", Races);
		}
	}

	class Tournament {
		public Day[] Days { get; private set; }
		public Tournament(Day[] days) {
			this.Days = (Day[]) days.Clone();
		}

		public static List<Tournament> CreateTournament(List<Day> dayList, int daysPerTournament) {
			List<Tournament> tournaments = new List<Tournament>();
			CreateTournament (tournaments, dayList, new Day[daysPerTournament], 0, 0);
			return tournaments;
		}

		private static void CreateTournament(List<Tournament> tournaments, List<Day> days, Day[] current, int index, int taken) {
			if (taken == current.Length) {
				tournaments.Add (new Tournament (current));

				Console.WriteLine (tournaments.Last () + "\n\n");
				return;
			}
			if (index >= days.Count)
				return;
			if (current.Length - taken > days.Count - index)
				return;
			CreateTournament (tournaments, days, current, index + 1, taken);
			if (!current.Take (taken).Any (c => c.Collide (days [index]))) {
				current [taken] = days [index];
				CreateTournament (tournaments, days, current, index + 1, taken + 1);
			}
		}

		public override string ToString ()
		{
			return string.Join<Day> (Environment.NewLine, Days);
		}
	}
}
Auf diesen Beitrag antworten »
Karlito

Verstehe ich es richtig, dass es eigentlich recht einfach ist, die 4er-Gruppen zu ermitteln, das Problem aber darin besteht, pro Tag 3 Rennen zu machen wobei ein Hase nie 2 mal an einem Tag rennen darf?

Gruß,

Karlito
Auf diesen Beitrag antworten »
eulerscheZahl

Ja, oder dass du an zwei Tagen das selbe Rennen aus 4 Hasen hast.
Die einzelnen Tage zu ermitteln geht noch recht flott, für die gegebenen Werte (12 Hasen, 3 Rennen) könne ich auf 5775 Möglichkeiten für einen einzelnen Tag.
Aber dann muss man davon 165 Tage auswählen, sodass kein Rennen doppelt ist. Wird wohl auf einen LP Solver hinauslaufen.
 
Auf diesen Beitrag antworten »
Karlito

Ich würde einen genetischen Algorithmus probieren. Damit schonmal rumgespielt? Wäre eine Premiere für mich. Kennst Du Gegenargumente?

Gruß,

Karlito
Auf diesen Beitrag antworten »
eulerscheZahl

Ein randomisierter Ansatz könnte klappen. Hängt davor ab, wie viele Lösungen es gibt. Die einzige zu finden wird schwer, da bist du mit Bruteforce evtl sogar besser beraten.
Meine Masterarbeit geht auch in die Richtung, aber nicht für Hasenrennen.

CodinGame ist eine gute Anlaufstelle, um damit herumzuspielen.
Hier sind soweit ich weiß alles randomisierte Algorithmen (Monte Carlo, genetische Algorithmen). Die finden ganz gute Züge.
Auf diesen Beitrag antworten »
Karlito

OK. Wenn ich am WE Zeit finde, probiere ich mal einen Lösungsversuch mit einem evolutionären Algorithmus.

Gruß,

Karlito
Auf diesen Beitrag antworten »
grohfuda

Würde es helfen (bzw. das Programm beschleunigen), wenn man festlegt, das Hase 1 immer im ersten Rennen des Tages läuft?

Viele Grüße
grohfuda
Auf diesen Beitrag antworten »
Karlito

Nicht wirklich. Wenn man systematisch nach einer Lösung sucht, würde man eh damit beginnen.

Gruß,

Karlito
 
Neue Frage »
Antworten »


Verwandte Themen

Die Beliebtesten »
Die Größten »
Die Neuesten »