Add files via upload

This commit is contained in:
Peter Norvig 2018-09-26 18:02:52 -07:00 committed by GitHub
parent 17e02692cd
commit 7445a8399c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -62,9 +62,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# `all_pairs(P)`\n",
"# All Pairs of Players\n",
"\n",
"We will generate all pairs of players like this:"
"We will generate all partner pairs of players like this:"
]
},
{
@ -144,7 +144,7 @@
"\n",
"# `make_games(pairs)`\n",
"\n",
"Now let's take those pairs and place them together into games. We'll choose one pair of players, `A`, and then another pair `B` such that between them there are 4 different players. Then we'll try to make `other_games` out of the remaining pairs. If we can't, we'll make a different choice for `B`. "
"Now let's take those pairs and place them together into games. We'll choose one pair of players, `A`, to play against another pair `B`, making sure that between the two pairs there are four different players. Then we'll try to make `other_games` out of the remaining pairs. If we can't, we'll make a different choice for `B`. "
]
},
{
@ -266,9 +266,9 @@
"source": [
"That looks good. Note that `make_games` does not ensure that each player plays every other player twice—we'll worry about that later.\n",
"\n",
"# `schedule(games, courts)`\n",
"# Scheduling Games to Courts\n",
"\n",
"Now we need to schedule games onto courts, such that no player plays twice in any round, and we take as few rounds as possible. We'll define `schedule` to produce a `list` of rounds, where each round is a tuple of up to `courts` games. We'll use a greedy approach to assigning games to rounds; this may result in more rounds than is optimal."
"Now we need to schedule games onto courts in rounds, such that no player plays twice in any round, and we take as few rounds as possible. We'll define `schedule` to produce a `list` of rounds, where each round is a tuple of up to `courts` games. We'll use a greedy approach to assigning games to rounds; this does *not* guarantee the shortest possible schedule."
]
},
{
@ -405,6 +405,7 @@
" print(fmt(row, *[c or '-' for c in counts], sum(counts) / 2))\n",
" \n",
"def games_str(round):\n",
" \"A string representing a round of games.\"\n",
" return ' | '.join('{:X},{:X} vs {:X},{:X}'\n",
" .format(a, b, c, d) for ((a, b), (c, d)) in round)\n",
" \n",
@ -791,7 +792,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"That's a very good schedule. It takes the minimum 15 rounds, and while not everyone plays everyone else 2 times, most counts are in the 1 to 3 range (except for pesky player 1, who faces 0 and B four times, and F zero times, and players 8 and B, who also do not play each other)."
"That's a good schedule. It takes the minimum 15 rounds, and although not all counts are 2, most are in the 1 to 3 range."
]
},
{
@ -800,19 +801,22 @@
"source": [
"# Addendum: Counting Schedules\n",
"\n",
"A reader asked \"*couldn't you have tried all possible schedules?*\" That's a great question! As [Ken Thompson says](https://users.ece.utexas.edu/~adnan/pike.html), \"when in doubt, use brute force.\" How many possible schedules are there? My first inclination was \"too many,\" even for *P* = 9, but is that really true? I'll count the number of schedules, approximately (that is, my formula will work exactly only for *P* where there is an even number of pairs and every round fills all the courts).\n",
"A reader asked \"*couldn't you have tried all possible schedules?*\" That's a great question! As [Ken Thompson says](https://users.ece.utexas.edu/~adnan/pike.html), \"when in doubt, use brute force.\" How many possible schedules are there? \n",
"\n",
"- For *P* players, there are *P* × (*P* - 1) / 2 pairs of players.\n",
"- We can place these pairs into the schedule in any order, so take the factorial of the number of pairs.\n",
"- But that over-counts, because order doesn't matter in the following ways:\n",
"- The order of pairs within a game doesn't matter, so divide by 2 (for each game).\n",
"- The order of games within a round doesn't matter, so divide by the factorial of the number of courts (for each round).\n",
"- The order of rounds in the schedule doesn't matter, so divide by the factorial of the number of rounds."
"- Assume a schedule with *R* rounds on *C* courts, with every court filled on every round.\n",
"- That means there are *G* = *CR* games and 2*G* slots in the schedule for pairs to fill.\n",
"- We can fill those slots with pairs in (2*G*)! ways.\n",
"- But that over-counts, because order doesn't matter in the following three ways:\n",
" - The order of pairs within a game doesn't matter, so divide by 2*<sup>G</sup>*.\n",
" - The order of games within a round doesn't matter, so divide *C*!*<sup>R</sup>*.\n",
" - The order of rounds in the schedule doesn't matter, so divide by *R*!.\n",
"\n",
"That gives us:"
]
},
{
"cell_type": "code",
"execution_count": 50,
"execution_count": 65,
"metadata": {
"collapsed": false
},
@ -820,37 +824,40 @@
{
"data": {
"text/plain": [
"{4: 15,\n",
" 5: 945,\n",
" 6: 2027025,\n",
" 7: 13749310575,\n",
" 8: 28845653137679503125,\n",
" 9: 7637693625347175036443671875}"
"{4: 15.0,\n",
" 5: 945.0,\n",
" 8: 2.8845653137679503e+19,\n",
" 9: 7.637693625347176e+27,\n",
" 12: 4.375874524269406e+66,\n",
" 13: 2.53276118507763e+83,\n",
" 16: 8.78872489906208e+147,\n",
" 17: 1.1985831550364023e+174}"
]
},
"execution_count": 50,
"execution_count": 65,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from math import factorial as fact\n",
"from math import factorial\n",
"\n",
"def combos(P):\n",
" pairs = P * (P - 1) // 2 \n",
" games = pairs // 2\n",
" courts = P // 4\n",
" rounds = games // courts\n",
" return fact(pairs) // 2 ** games // fact(courts) ** rounds // fact(rounds)\n",
"def schedules(P):\n",
" \"Number of possible schedules for P players with all courts full.\"\n",
" G = P * (P - 1) // 4 # Number of games\n",
" C = P // 4 # Number of courts\n",
" R = G // C # Number of rounds\n",
" return factorial(2 * G) / 2 ** G / factorial(C) ** R / factorial(R)\n",
"\n",
"{P: combos(P) for P in range(4, 10)}"
"{P: schedules(P) \n",
" for P in (4, 5, 8, 9, 12, 13, 16, 17)}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We see that it would have been feasible to try every schedule up to *P*=7, but not for any *P* beyond that."
"We see that it would have been infeasible to try every schedule, even for *P*=8, let alone 9 or 16."
]
}
],