기존 round-robin은 운에 따라 부서 분포 max-min=2 발생 (예: HPC 2,1,0,1,1,2,1). ceil 슬롯을 ceil_count 적은 팀에 우선 배정하여 모든 부서 max-min ≤ 1 보장. 결과: - EffTech [1,2,2,2,2,2,1] - System [2,1,1,1,1,1,1] - HPC [1,1,1,1,1,1,2] - Data [1,1,1,1,0,1,1] - Platform [0,0,0,0,1,0,0] (1명) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
143 lines
4.4 KiB
Python
143 lines
4.4 KiB
Python
"""
|
|
참가자 35명 → 7팀 (팀당 5명) 배정.
|
|
같은 부서 2명 이하 제약. 랜덤 시드로 재현 가능.
|
|
결과: participants.json (이름→팀 매핑) + 콘솔 출력.
|
|
"""
|
|
import json
|
|
import random
|
|
from collections import Counter, defaultdict
|
|
from pathlib import Path
|
|
|
|
PEOPLE = [
|
|
("한지승", "MLOps Platform"),
|
|
("변수민", "MLOps Data"),
|
|
("박재호", "MLOps Data"),
|
|
("김태현", "MLOps Data"),
|
|
("강승형", "MLOps Data"),
|
|
("손현준", "MLOps Data"),
|
|
("김동국", "MLOps Data"),
|
|
("김재현", "MLOps HPC"),
|
|
("이준석", "MLOps HPC"),
|
|
("오근현", "MLOps HPC"),
|
|
("김정명", "MLOps HPC"),
|
|
("김영관", "MLOps HPC"),
|
|
("유용혁", "MLOps HPC"),
|
|
("최호진", "MLOps HPC"),
|
|
("전효준", "MLOps HPC"),
|
|
("김병훈", "MLOps System"),
|
|
("이지환", "MLOps System"),
|
|
("서희", "MLOps System"),
|
|
("정채윤", "MLOps System"),
|
|
("장혁진", "MLOps System"),
|
|
("장다현", "MLOps System"),
|
|
("박영훈", "MLOps System"),
|
|
("길주현", "MLOps System"),
|
|
("조민정", "AI Efficiency Tech"),
|
|
("김민섭", "AI Efficiency Tech"),
|
|
("김호승", "AI Efficiency Tech"),
|
|
("서한배", "AI Efficiency Tech"),
|
|
("심성환", "AI Efficiency Tech"),
|
|
("유준희", "AI Efficiency Tech"),
|
|
("이성재", "AI Efficiency Tech"),
|
|
("이재광", "AI Efficiency Tech"),
|
|
("이정태", "AI Efficiency Tech"),
|
|
("이준형", "AI Efficiency Tech"),
|
|
("정현준", "AI Efficiency Tech"),
|
|
("유지원", "AI Efficiency Tech"),
|
|
]
|
|
|
|
NUM_TEAMS = 7
|
|
TEAM_SIZE = 5
|
|
SEED = 20260428 # 행사일 시드 (재현 가능)
|
|
|
|
|
|
def assign(seed):
|
|
"""
|
|
부서별 균등 분배 + 팀 사이즈 5 보장.
|
|
|
|
각 부서 N명 → q명 모든 팀 + r명 추가 (q, r = divmod(N, NUM_TEAMS)).
|
|
추가 r명 받을 팀은 "지금까지 추가 적게 받은 팀" 우선 → 모든 팀 정확히 같은 횟수만큼 ceil 받음.
|
|
|
|
효과:
|
|
- 부서별 분포: max - min ≤ 1 (균등)
|
|
- 모든 팀 정확히 5명
|
|
- EffTech 12명: 5팀이 2명, 2팀이 1명 (모든 팀 ≥1)
|
|
"""
|
|
rng = random.Random(seed)
|
|
by_dept = defaultdict(list)
|
|
for name, dept in PEOPLE:
|
|
by_dept[dept].append(name)
|
|
|
|
for d in by_dept:
|
|
rng.shuffle(by_dept[d])
|
|
|
|
depts_sorted = sorted(by_dept.keys(), key=lambda d: -len(by_dept[d]))
|
|
teams = [[] for _ in range(NUM_TEAMS)]
|
|
ceil_count = [0] * NUM_TEAMS # 각 팀이 받은 ceil 횟수
|
|
|
|
for dept in depts_sorted:
|
|
members = by_dept[dept]
|
|
n = len(members)
|
|
q, r = divmod(n, NUM_TEAMS)
|
|
|
|
if r > 0:
|
|
# ceil_count 적은 팀 우선, tie는 random
|
|
order = sorted(range(NUM_TEAMS), key=lambda i: (ceil_count[i], rng.random()))
|
|
ceil_teams = set(order[:r])
|
|
else:
|
|
ceil_teams = set()
|
|
|
|
idx = 0
|
|
for ti in range(NUM_TEAMS):
|
|
count = q + (1 if ti in ceil_teams else 0)
|
|
for _ in range(count):
|
|
teams[ti].append((members[idx], dept))
|
|
idx += 1
|
|
if ti in ceil_teams:
|
|
ceil_count[ti] += 1
|
|
|
|
return teams
|
|
|
|
|
|
def main():
|
|
assert len(PEOPLE) == NUM_TEAMS * TEAM_SIZE, (
|
|
f"인원수 불일치: {len(PEOPLE)}명, 기대 {NUM_TEAMS * TEAM_SIZE}명"
|
|
)
|
|
|
|
teams = assign(SEED)
|
|
print(f"# 시드 {SEED} (round-robin 결정적 배정)\n")
|
|
|
|
# 부서별 분포 검증
|
|
dept_dist = defaultdict(list)
|
|
for team in teams:
|
|
team_counts = Counter(d for _, d in team)
|
|
for dept in {d for _, d in PEOPLE}:
|
|
dept_dist[dept].append(team_counts.get(dept, 0))
|
|
|
|
print("# 부서별 팀 분배 (max - min ≤ 1 = 균등)")
|
|
for dept, dist in sorted(dept_dist.items(), key=lambda x: -sum(x[1])):
|
|
print(f" {dept}: {dist} (총 {sum(dist)}명)")
|
|
print()
|
|
|
|
mapping = {}
|
|
for i, team in enumerate(teams, 1):
|
|
team_name = f"팀{i}"
|
|
dept_counts = Counter(d for _, d in team)
|
|
dept_summary = ", ".join(f"{d.replace('MLOps ', '').replace('AI Efficiency Tech', 'AI Eff')} {c}" for d, c in dept_counts.items())
|
|
print(f"## {team_name} ({dept_summary})")
|
|
for name, dept in team:
|
|
print(f" - {name} ({dept})")
|
|
mapping[name] = team_name
|
|
print()
|
|
|
|
out = Path(__file__).parent / "participants.json"
|
|
out.write_text(
|
|
json.dumps(mapping, ensure_ascii=False, indent=2),
|
|
encoding="utf-8",
|
|
)
|
|
print(f"저장: {out}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|