Reputation: 39
Problem:
Example:
IF
S = {a, b, c, d, e, f, g, h, i, j}
L = func(S)
THEN
L == [
{ {a, b, c, d, e}, {f, g, h, i, j} },
{ {a, b, c, d, f}, {e, g, h, i, j} },
{ {a, b, c, d, g}, {f, e, h, i, j} },
... ]
SUCH THAT
{ {a, b, c, d, e}, {f, g, h, i, j} }
== { {f, g, h, i, j}, {a, b, c, d, e} }
== { {e, d, a, b, c}, {g, i, j, f, h} }
Purpose: I need to list all possible ways a variable number of players can be divided into two equal (or almost equal) teams.
What I tried so far: I was able to code this in python using the itertools.combinations
function. However, the way I did it seems inefficient. I got all combination for one subset and got the second subset by subtracting the original set from the first subset. But, because I need to take consideration of the fact that which team the player gets into does not matter, I have to basically divide that combination in half.
This is what I had.
import itertools as it
import math
def divide(players: set[int]):
comb = it.combinations(players, math.floor(len(players) / 2))
rtn = []
for team in comb:
a = frozenset(team)
b = frozenset(players - a)
element = {a, b}
if element not in rtn:
rtn.append(element)
return rtn
Upvotes: 0
Views: 455
Reputation: 80197
You are almost here.
Remove the first element from the players and remember it as leader
Form commands from players as you do now.
Add leader
to the first command just before output
Simple example (without sets)
import itertools as it
import math
def divide(players):
first = players.pop(0)
comb = it.combinations(players, len(players) // 2)
rtn = []
for team in comb:
a = list(team)
a.insert(0, first)
b = [x for x in players if x not in team]
element = (a, b)
if element not in rtn:
rtn.append(element)
return rtn
print(divide([1,2,3,4,5]))
[([1, 2, 3], [4, 5]), ([1, 2, 4], [3, 5]),
([1, 2, 5], [3, 4]), ([1, 3, 4], [2, 5]),
([1, 3, 5], [2, 4]), ([1, 4, 5], [2, 3])]
Upvotes: 1
Reputation: 89
You should try with a backtracking. It's quick and uses very few lines!
n = int(input())
# List of solutions
# For each l in L, l[i] = True if player i is in team A, False if he is in team B
L = []
# Current solution
cur = [False]*n
# In each step, we decide the team of player i,
# Given that team A has already n_team_a players
def backtracking(i, n_team_a):
n_team_b = i - n_team_a # Number of players on team B
left = n - i # Number of players left to choose
# If we can't have a balanced team even if we put all the players
# left in the same team, abort
if n_team_a + left + 1 < n_team_b or n_team_b + left + 1 < n_team_a:
return
# If we found a solution, add it to L
if i == n:
L.append(cur.copy())
return
# Try putting player i on team A
cur[i] = True
backtracking(i + 1, n_team_a + 1)
# Try putting player i on team B
cur[i] = False
backtracking(i + 1, n_team_a)
# Start
backtracking(0, 0)
# Print solutions
print(*L, sep='\n')
Upvotes: 1