Skip to content

Commit b947934

Browse files
authored
Merge pull request #55 from bsa0322/jy/union-find/py
[유니온 파인드] 05월 26일 (필수 + 선택)
2 parents 4fa8612 + 74149ce commit b947934

File tree

7 files changed

+394
-0
lines changed

7 files changed

+394
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import sys
2+
sys.setrecursionlimit(10**6)
3+
input = sys.stdin.readline
4+
5+
"""
6+
[거짓말]
7+
8+
1. 각 사람들은 다양한 파티를 통해 연결됐다고 할 수 있음
9+
2. 연결된 사람들은 같은 집합에 속함
10+
3. 각 집합에 속한 사람들 중 한 명이라도 진실을 안다면 그 집합의 사람들이 속한 파티에는 거짓말을 할 수 없음
11+
-> 유니온 파인드로 사람들을 집합으로 묶은 뒤, 파티마다 거짓말을 할 수 있는지 확인하기
12+
-> 이때, 진실을 아는 사람들의 루트 정점을 0으로 설정해서 유니온 파인드를 통해 집합으로 묶고 시작
13+
-> 0과 같은 집합이 아니어야 거짓말을 할 수 있음
14+
15+
!주의! 파티 정보를 입력받으며 바로 거짓말 가능 여부를 판단할 수 없음 (예제 입력 4)
16+
각 파티에서 한 사람만 저장해둔 뒤, 마지막에 거짓말 가능 여부 한 번에 판단
17+
"""
18+
19+
# find 연산
20+
def find_parent(x):
21+
if parent[x] < 0:
22+
return x
23+
parent[x] = find_parent(parent[x])
24+
return parent[x]
25+
26+
# union 연산
27+
def union(x, y):
28+
px = find_parent(x)
29+
py = find_parent(y)
30+
31+
if px == py:
32+
return
33+
34+
if parent[px] < parent[py]:
35+
parent[px] += parent[py]
36+
parent[py] = px
37+
else:
38+
parent[py] += parent[px]
39+
parent[px] = py
40+
return
41+
42+
def count_liar_party(party):
43+
cnt = 0
44+
45+
for i in party:
46+
if find_parent(i) != find_parent(0):
47+
cnt += 1
48+
49+
return cnt
50+
51+
# 입력
52+
n, m = map(int, input().split())
53+
parent = [-1] * (n+1) # 초기화
54+
55+
party = [] # 각 파티의 대표자 저장할 리스트
56+
57+
# 진실을 아는 사람들
58+
for i in map(int, input().split()[1:]):
59+
union(i, 0)
60+
61+
# 각 파티에 대한 입력 & 연산
62+
for _ in range(m):
63+
arr = list(map(int, input().split()))
64+
party.append(arr[1]) # 파티 정보로 각 파티의 첫번째 사람만 저장
65+
for i in range(2, arr[0] + 1):
66+
union(arr[i], arr[1])
67+
68+
# 연산 & 출력
69+
print(count_liar_party(party))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import sys
2+
input = sys.stdin.readline
3+
4+
"""
5+
[2048 (Easy)]
6+
7+
- 상, 하, 좌, 우로 이동하는 경우에 대해 최대 5번 이동시키는 모든 경우를 구한 후, 가장 큰 블록 찾는 문제 - 백트래킹
8+
- 움직이는 함수는 하나만 짜고, 보드를 돌려가면서 상, 하, 좌, 우 모든 방향의 움직임을 만듦
9+
10+
- 상 <-> 하: 행 순서를 뒤집어서 해결
11+
- 상/하 <-> 좌/우: Transpose Matrix 활용
12+
13+
- ex. 2 2 1 를 상, 하, 좌, 우로 이동하는 경우 구하는 법
14+
2 2 2
15+
4 4 4
16+
-상: 원래 배열에서 상으로 움직이는 함수 실행
17+
2 2 1 4 4 1
18+
2 2 2 -> 4 4 2
19+
4 4 4 0 0 4
20+
-하: 원래 배열의 행 순서를 뒤집은 후, 상으로 움직이는 함수 실행
21+
2 2 1 4 4 4 4 4 4
22+
2 2 2 -> 2 2 2 -> 4 4 2
23+
4 4 4 2 2 1 0 0 1
24+
-좌: 원래 배열의 전치 행렬을 구한 후, 상으로 움직이는 함수 실행
25+
2 2 1 2 2 4 4 4 8
26+
2 2 2 -> 2 2 4 -> 1 2 4
27+
4 4 4 1 2 4 0 0 0
28+
-우: 원래 배열의 전치 행렬에서 행 순서를 뒤집은 후, 상으로 움직이는 함수 실행
29+
2 2 1 1 2 4 1 4 8
30+
2 2 2 -> 2 2 4 -> 4 2 4
31+
4 4 4 2 2 4 0 0 0
32+
33+
- zip(): 두개 이상의 iterable한 객체를 인자로 받아서, 순서대로 하나씩 묶어서 반환한다.
34+
ex) zip([1, 2, 3], ['a', 'b', 'c']) -> [1, 'a'], [2, 'b'], [3, 'c']
35+
따라서 zip의 인자로 각 행을 넣어주면, 행과 열이 바뀐 Transpose matrix가 나오게 된다.
36+
"""
37+
38+
def up(board):
39+
"""
40+
위로 움직이는 함수
41+
한 열씩 검사하면서 위의 행부터 2개씩 같은 거 있다면 합치기
42+
이때 블록 없는 부분은 넘어가고, 블록이 존재했던 값을 저장해서 비교하는 것이 중요!
43+
"""
44+
temp = [[0]*n for _ in range(n)]
45+
for c in range(n):
46+
idx = 0
47+
prev = 0
48+
for r in range(n):
49+
if not board[r][c]:
50+
continue
51+
if board[r][c] == prev:
52+
temp[idx-1][c] *= 2
53+
prev = 0
54+
else:
55+
temp[idx][c] = board[r][c]
56+
prev = board[r][c]
57+
idx += 1
58+
59+
return temp
60+
61+
def backtracking(cnt, board):
62+
global ans
63+
if cnt == 5:
64+
for line in board:
65+
ans = max(ans, max(line))
66+
return
67+
68+
# Transpose matrix 구하기 (상 -> 좌)
69+
board_t = list(zip(*board))
70+
71+
# 상
72+
backtracking(cnt+1, up(board))
73+
# 하
74+
backtracking(cnt+1, up(board[::-1]))
75+
# 좌
76+
backtracking(cnt+1, up(board_t))
77+
# 우
78+
backtracking(cnt+1, up(board_t[::-1]))
79+
80+
return
81+
82+
# 입력
83+
n = int(input())
84+
board = [list(map(int, input().split())) for _ in range(n)]
85+
86+
ans = 0
87+
backtracking(0, board)
88+
89+
# 출력
90+
print(ans)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import sys
2+
input = sys.stdin.readline
3+
4+
"""
5+
[화살표 연산자]
6+
7+
1. n이 1보다 큰 홀수인 경우 -> ERROR
8+
2. n이 1인데 x가 음수인 경우 -> while문 조건 항상 참 -> INFINITE
9+
3. n이 1인데 x가 양수인 경우 or x가 0보다 작거나 같은 경우 -> while문에 진입 못함 -> 0
10+
4. n이 0인데 x가 양수인 경우 -> while문 조건 항상 참 -> INFINITE
11+
5. 나머지 경우엔 (x-1)를 n//2로 나눈 몫을 출력
12+
- 연산했을 때 1 이상이 남을 때까지만 출력을 할 수 있으므로
13+
"""
14+
15+
def solution(x, n):
16+
if n > 1 and n % 2:
17+
return "ERROR"
18+
if n == 1 and x < 0:
19+
return "INFINITE"
20+
if n == 1 or x <= 0:
21+
return 0
22+
if n == 0:
23+
return "INFINITE"
24+
return (x - 1) // (n // 2)
25+
26+
# 입력
27+
x, n = map(int, input().split())
28+
29+
# 연산 & 출력
30+
print(solution(x, n))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import sys
2+
sys.setrecursionlimit(10**6)
3+
input = sys.stdin.readline
4+
5+
"""
6+
[사이클 게임]
7+
8+
사이클이 발생한 순간 = 같은 집합에 있는 원소 두 개를 유니온하려 할 때
9+
union 함수의 리턴값을 boolean으로 주어 cycle이 생성되는 순간 발견하기
10+
"""
11+
12+
# find 연산
13+
def find_parent(x):
14+
if parent[x] < 0:
15+
return x
16+
parent[x] = find_parent(parent[x])
17+
return parent[x]
18+
19+
# union 연산
20+
def union(x, y):
21+
px = find_parent(x)
22+
py = find_parent(y)
23+
24+
if px == py:
25+
return False
26+
27+
if parent[px] < parent[py]:
28+
parent[px] += parent[py]
29+
parent[py] = px
30+
else:
31+
parent[py] += parent[px]
32+
parent[px] = py
33+
34+
return True
35+
36+
# 입력
37+
n, m = map(int, input().split())
38+
parent = [-1]*n # 초기화
39+
40+
for i in range(m):
41+
x, y = map(int, input().split())
42+
if not union(x, y):
43+
# 사이클이 생성됨
44+
print(i+1)
45+
break
46+
else: # for-else문: for문이 break에 걸리지 않고 정상 종료된 경우에만 else문 실행
47+
print(0)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import sys
2+
sys.setrecursionlimit(10**6)
3+
input = sys.stdin.readline
4+
5+
"""
6+
[할로윈의 양아치] - pypy3로 제출
7+
8+
- weighted union find -> 루트 정점에 아이들의 수(집합 원소 수)와 사탕 개수까지 쌍으로 저장하기
9+
- dp(냅색)으로 K명 미만의 아이들에게서 뺏을 수 있는 최대 사탕 수 구하기
10+
"""
11+
12+
# find 연산
13+
def find_parent(x):
14+
if parent[x][0] < 0:
15+
return x
16+
parent[x][0] = find_parent(parent[x][0])
17+
return parent[x][0]
18+
19+
# union 연산
20+
def union(x, y):
21+
px = find_parent(x)
22+
py = find_parent(y)
23+
24+
if px == py:
25+
return
26+
27+
if parent[px][0] < parent[py][0]:
28+
parent[px][0] += parent[py][0]
29+
parent[px][1] += parent[py][1]
30+
parent[py][0] = px
31+
else:
32+
parent[py][0] += parent[px][0]
33+
parent[py][1] += parent[px][1]
34+
parent[px][0] = py
35+
return
36+
37+
def knapsack(k):
38+
dp = [0] * k # 1부터 k-1까지
39+
count = [] # [아이들의 수, 사탕의 수]
40+
for p, c in parent:
41+
if p < 0:
42+
count.append((-p, c))
43+
44+
for child_cnt, candy_cnt in count:
45+
for i in range(k-1, child_cnt-1, -1):
46+
dp[i] = max(dp[i], dp[i-child_cnt] + candy_cnt)
47+
48+
return dp[-1]
49+
50+
# 입력
51+
n, m, k = map(int, input().split())
52+
parent = [[-1, i] for i in map(int, ("0 "+input()).split())] #[-아이들의 수, 사탕 개수]
53+
54+
for _ in range(m):
55+
a, b = map(int, input().split())
56+
union(a, b)
57+
58+
# 연산 & 출력
59+
print(knapsack(k))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import sys
2+
sys.setrecursionlimit(10**6)
3+
input = sys.stdin.readline
4+
5+
"""
6+
[친구 네트워크]
7+
8+
1. weighted union find -> 루트 정점에 친구의 수(집합 원소 수) 저장
9+
2. 친구 네트워크에 몇 명 있는지 구하기 -> 루트 정점의 parent값 접근
10+
11+
!주의! 정점이 문자열로 들어오므로 map을 활용해 string을 int로 매핑
12+
"""
13+
14+
# find 연산
15+
def find_parent(x):
16+
if parent[x] < 0:
17+
return x
18+
parent[x] = find_parent(parent[x])
19+
return parent[x]
20+
21+
# union 연산
22+
def union(x, y):
23+
px = find_parent(x)
24+
py = find_parent(y)
25+
26+
if px == py:
27+
return
28+
29+
if parent[px] < parent[py]:
30+
parent[px] += parent[py]
31+
parent[py] = px
32+
else:
33+
parent[py] += parent[px]
34+
parent[px] = py
35+
return
36+
37+
# 입력
38+
t = int(input())
39+
40+
for _ in range(t):
41+
# 입력
42+
f = int(input())
43+
44+
# 초기화
45+
name_to_idx = dict()
46+
idx = 0
47+
parent = [-1] * (2 * f) # 입력이 모두 다른 이름으로 들어올 경우 -> 최대 2*f개
48+
49+
for _ in range(f):
50+
a, b = input().split()
51+
52+
if a not in name_to_idx:
53+
name_to_idx[a] = idx
54+
idx += 1
55+
if b not in name_to_idx:
56+
name_to_idx[b] = idx
57+
idx += 1
58+
59+
x, y = name_to_idx[a], name_to_idx[b]
60+
61+
union(x, y)
62+
63+
print(-parent[find_parent(x)])

0 commit comments

Comments
 (0)