2021. 2. 10. 15:15ㆍAlgorithm/Python
해당 알고리즘 문제는 BOJ(BAEKJOON ONLINE JUDGE)의 17528번: Two Machines (acmicpc.net)를 참고 하였으며, 해당 글은 이용 규칙 (acmicpc.net)을 준수하였음을 알려드립니다.
Two Machines 문제를 풀기 위해서, 다음과 같이 아이디어를 생각했다.
i = 1일때, 리스트 a와 b에 요소 하나 씩 입력받아 최솟값을 구한다.
예를들어, \(a_1\)=[2], \(b_1\)=[3] 일때, A Machine으로 작업을 했다면 t = 2 B Machine으로 작업을 했다면 t = 3 이 되고 둘 중 최솟값인 t=2를 출력하게 된다.
i = 2일때, 리스트 a와 b에 요소 두개 씩 입력받아 최솟값을 구한다.
예를들어 \(a_1\)=[2,5], \(b_1\)=[3,3] 일때
- A Machine으로만 작업을 했다면 \(t_1\) = 2, \(t_2\) = 5 \(\Rightarrow\) 7시간
- B Machine으로만 작업을 했다면 \(t_1\) = 3, \(t_2\) = 3 \(\Rightarrow\) 6시간
- A Machine\((a_1)\)과 B Machine\((b_2)\)으로 하나씩 작업을 했다면 \(t_1\) = 2, \(t_2\) = 3 \(\Rightarrow\) 3시간
- B Machine\((b_1)\)과 A Machine\((a_2)\)으로 하나씩 작업을 했다면 \(t_1\) = 3, \(t_2\) = 5 \(\Rightarrow\) 5시간
i = 1, i = 2를 각 각 그림으로 표현하면,
마찬가지로 i = 3 일때를 그림으로 표현하면 다음과 같다.
그림에서 확인 할 수 있듯이 알고리즘의 순서를 표현하면 다음과 같다.
1. a와 b로 만들 수 있는 조합을 나열한다. 조합의 개수는 \(2^i)개가 된다.
2. a는 a끼리 더하고 b는 b끼리 각각 더해주고 난후 Max(\(\sum a_i , \sum b_i\)) 값을 구한다.(모든 일이 끝나는 t를 구하기 위해서)
3. 각각의 Max값을 비교하여 그 중 가장 작은 값이 출력 값이 된다.
먼저 1을 코딩하기 위해서 입력받은 list(\(a_i\),\(b_i\))로 만들수 있는 조합을 나열해야한다. 대표적으로 다음 두가지 방법을 이용한다.
1) itertools 라이브러리를 이용하여 조합 구하기.
python에서는 순열,조합을 쉽게해주는 itertools 라이브러리가 있다. 순열을 할 때는 permutations를 import하고 조합을 할 때는 combinations를 import한다.
예를들어 list [1,2,3,4]중에 중복을 허용하지 않고 2개를 뽑는다고 했을때 다음과 같이 나타낸다.
1
2
3
4
5
6
|
a=[1,2,3,4]
from itertools import combinations
for i in combinations(a, 2):
print(i, end=" ")
|
cs |
출력 : (1,2)(1,3)(1,4)(2,3)(2,4)(3,4)
2) 재귀호출로 직접 알고리즘 작성
재귀호출은 내가 만든 함수에 다시 그 함수를 넣어서 종료조건을 만날때까지, 실행하는 경우를 이야기한다.
예를들어 Hellow!를 n번 추출한다고 해보자.
1
2
3
4
5
6
7
8
9
10
|
def hello(count):
if count == 0:
return
print('Hello!',count)
count -= 1
hello(count)
hello(5)
|
cs |
위 코드를 실행하면
Hello! 5
Hello! 4
Hello! 3
Hello! 2
Hello! 1
처럼 출력이된다. 이 원리를 그림으로 표현하면 다음과 같다.

hello(5)가 실행이되면 Hello(4)를 호출하고 실행한다. 이런식으로 종료조건을 만날때까지 반복이된다.
알고리즘 코딩 테스트는 라이브러리를 쓰지 못하기 때문에 조합과정을 직접 코딩해야한다.
1
2
3
4
5
6
7
8
9
|
def combination(lst,n):
for i in range(len(lst)):
if n == 1:
yield [lst[i]]
for j in combination(lst[i+1:], n-1):
yield [lst[i]] + j
for i in combination(a,2):
print(i,end="")
|
cs |
[1,2][1,3][1,4][2,3][2,4][3,4]
내가 직접 작성한 코드를 보면 n == 1이라는 종료조건을 가진 재귀호출 알고리즘이다. 이렇게 조합 알고리즘을 직접 만들고나서 전체적인 코드를 작성하였다.
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
|
t = int(input())
a_i_com=[]
b_i_com=[]
t_max=[]
dp = [[0] for i in range(2**t)]
a_i = []
b_i = []
for i in range(t):
a_i_, b_i_ = map(int, input().split())
a_i.append(a_i_)
b_i.append(b_i_)
def combination(lst,n):
for i in range(len(lst)):
if n == 1:
yield [lst[i]]
for j in combination(lst[i+1:], n-1):
yield [lst[i]] + j
for j in range(1,t+1):
for i in combination(a_i,j):
a_i_com.append(sum(i))
for i in combination(b_i,j):
b_i_com.append(sum(i))
dp[0]=[a_i_com[-1],0]
dp[2**t-1]=[0,b_i_com[-1]]
for i in range(1,2**t-1):
dp[i] = [a_i_com[i-1],b_i_com[(2**t-2)-i]]
for i in range(len(dp)):
t_max.append(max(dp[i]))
min(t_max)
|
cs |
위와 같은 코드로 jupyternote에서는 이상없이 잘 실행된다. 하지만 BOJ 홈페이지에서는 시간초과가 나왔다. 아무래도 재귀호출에는 호출한만큼의 for문이 쓰이기 때문에 시간초과가 발생한거 같다. 그래서 혼자 계속 고민하다가 C++을 사용하여 문제를 푼사람들의 아이디어를 찾아보았고 괜찮은 아이디어를 발견했다.
blog.naver.com/PostView.nhn?blogId=njw1204&logNo=221669613809
\(a_i\)를 무게로(Weight) \(b_i\)를 가치(Value)로 생각해서 냅색(Knapsack)문제로 해결했다는 아이디어다. 냅색으로 생각하고 풀면 확실히 Over time이 개선이 될것이다. 괜찮은 아이디어라고 생각하고 알고리즘을 짜봤는데 가방의무게한도 K 가 이 문제에서는 어떻게 적용해야할지 모르겠다... 따라서 다음 알고리즘 포스팅에서는 냅색알고리즘을 한번 정리해야겠다.
'Algorithm > Python' 카테고리의 다른 글
백준 14710 문제 (0) | 2021.02.08 |
---|