- 개요
- 동전 교환 문제
- 평균적인 대기 시간을 최소로 하는 작업 스케쥴링
- 회의실 배정 문제
- 배낭 문제
주어진 제약 조건을 만족하는 최적인 해를 구하는 문제(최적화 문제)에 주로 적용하는 방법
최적화 문제란?
주어진 문제의 해는 일련의 선택 (x1, x2, x3, ..., xn)으로 나타낼 수 있고, 단계별로 하나씩 xi 를 결정함.
각 단계에서, 현재 상태에서 가장 좋다고 판단되는 결정을 함.
욕심장이 방법은 전체적인 입장에서 보지 않고 현재까지 선택한 상황(현 단계)에서 가장 최선으로 판단되는 결정을 함.
C : 후보들의 집합
Solution(S) : 특정한 후보들의 집합 S가 주어진 문제의 해인지를 결정하는 함수
Feasible(S) : 특정한 후보들의 집합 S가 문제의 해가 될 수 있는 가능성이 있는지를 결정하는 함수
Select(S) : 남아 있는 후보들의 집합 C에서 현 상태에서 가장 좋은 후보를 선택하는 함수 (어떤 기준을 갖고 선택하느냐가 굉장히 중요함)
pseudo code
Set function Greedy(Set C)
/*C : 후보들의 집합*/
{ S = ø;
while ( C ≠ ø and !Solution(S)) do // S가 해가 되거나 C가 공집합이 될 때까지 반복
{ x = Select(C); // 현 시점에서 가장 좋은 후보를 선택
C = C - {x}; // 선택한 후보를 후보들의 집합에서 제외시킴
if(Feasible(S U {x})) // 해가 될 가능성이 없으면 다시 위로,
S = S U {x}; // 해가 될 가능성이 있으면 S에 넣기
}
if(Solution(S))
return S // 문제의 해라면, S를 반환
else
return ø
}
목적 함수 : 사용하는 동전들의 개수
후보들의 집합 C : 1원, 10원, ..., 500원 동전들
함수 Solution : 선택한 동전들의 합이 거스름 돈과 같은 경우 참(True)
함수 Feasible : 선택한 후보들의 합이 거스름 돈을 넘지 않을 경우 참(True)
함수 Selection : 후보들 중 가장 단위가 큰 동전을 선택 (선택의 기준)
ex) 동전 단위 (1원, 7원, 10원) 일때, 14원을 가장 적은 수의 동전으로 교환해주는 방법은?
Greedy Method
동적 계획법(?)
n개의 작업들 {1, 2, ..., n}이 있고, 각 작업 i를 처리하는데 걸리는 시간이 p(i)이다.
작업을 처리할 수 있는 server가 하나 있다고 가정한다.
작업들의 평균적인 대기시간을 최소로 하는 작업들의 처리 순서를 정하라.
ex-1. n = 6
처리 순서 ----------------->
작업 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
처리시간 p(i) | 3 | 4 | 1 | 8 | 2 | 6 |
대기 시간 | 0 | 3 | 7 | 8 | 16 | 18 |
처리하는 작업 순서 : 1, 2, 3, 4, 5, 6
모든 작업의 대기 시간 총 합
알 수 있는 점 : 처리 순서가 빠른게 다음 작업들에 영향을 미친다.
따라서 최적인 작업 처리 순서는 처리 시간이 적은 순서대로 처리하면 된다.
ex-2. n = 6
처리 순서 ----------------->
작업 | 3 | 5 | 1 | 2 | 6 | 4 |
---|---|---|---|---|---|---|
처리시간 p(i) | 1 | 2 | 3 | 4 | 6 | 8 |
대기 시간 | 0 | 1 | 3 | 6 | 10 | 16 |
모든 작업의 대기 시간 총합
처리시간이 작은 작업부터 차례대로 처리하면 평균적인 대기 시간이 최소가 된다.
증명 : 처리 순서를 i1, i2, ..., in이라고 하자.
이 처리 순서에서 j < k이고 p(ij) > p(ik)인 두 작업 ij, ik가 있다면(순서가 늦지만, 작업시간은 더 작은 경우), 이 작업의 순서를 교환하면, 대기시간 총 합이 늘지 않음을 보이면 된다.
즉, 처리 순서가 빠르지만 처리 시간이 긴 작업이 앞에 있을 때, 대기시간이 더 크고, 그 순서를 바꿔주면, 대기시간이 줄어든다.
한 개의 회의실이 있는데, 이를 사용하고자 하는 n개의 회의(activity)들에 대하여 각 회의 i의 시작시간 si와 끝나는 시간 fi가 주어져 있다. 각 회의가 겹치지 않게 하면서, 회의실을 사용할 수 있는 최대수의 회의를 찾아라. 단, 회의는 한 번 시작하면 중간에 중단될 수 없으며, 한 회의가 끝나는 것과 동시에 다음 회의가 시작될 수 있다.
ex. n = 12
회의 i | 시작시간 (si) | 끝나는 시간 (fi) |
---|---|---|
1 | 1 | 4 |
2 | 3 | 5 |
3 | 0 | 6 |
4 | 5 | 7 |
5 | 3 | 8 |
6 | 5 | 9 |
7 | 6 | 10 |
8 | 8 | 11 |
9 | 8 | 12 |
10 | 2 | 13 |
11 | 12 | 14 |
입력 : S = {(si, fi)|1 ≤ i ≤ n}
출력 : Solution
Algorithm Greedy Schedule(S, n)
Solution = {1};
Last = 1; // 마지막에 선택한 activity
for(int i = 2; i <= n; i++;)
if (Si >= flast)
{
Solution = Solution U {i};
Last = i;
}
성질 1 : 선택 회의 1(끝나는 시간이 가장 빠른 회의)를 포함하는 최적인 해 A가 반드시 존재한다.
증명 : 최적해 A = {i1, i2, ..., ik} : 최적인 해에 들어가는 회의들(끝나는 시간에 의하여 정렬)
i1 = 1일 경우 : 성립
i1 ≠ 1일 경우 : A' = (A - {i1}) U {1}에 속하는 모든 회의는 서로 겹치지 않는다. (i1을 빼고 대신 1을 넣는다.) 그러므로 회의 1을 포함하는 최적해가 있다.
-> 욕심쟁이 선택으로 시작하는 최적인 해가 존재한다.
성질 2 : A(회의 1을 포함)가 최적해라면, A' = A - {1}은 회의들 S' = {i가 S의 원소일 때 | si ≥ f1}에 대한 최적해이다.
정리 : 욕심쟁이 방법이 최적 해를 구한다.
증명 : 성질 1,2에 의하여 욕심쟁이 선택을 한 후 남은 문제는 원래 문제와 같은 형태의 최적화 문제가 된다. n에 대한 귀납법에 의하여 매 단계에서 욕심쟁이 선택을 하면 최적인 해를 얻는다.
용량이 M인 배낭이 있다. 그리고 이 배낭에 넣고자 하는 물건들이 n개 있다. 물건 i의 무게는 Wi이고, 이것을 배낭에 넣을 경우 Pi의 이익을 얻는다. 배낭에 넣는 물건들의 총 무게의 합이 M이 넘지 않도록 하면서 얻는 이익의 합이 최대가 되도록 하라.
다음 조건을 만족하면서 ∑PiXi(1≤i≤n)를 최대로 하는 (X1, X2, ..., Xn)을 구하라.
ex : n = 3, M = 20, (P1, P2, P3) = (25, 24, 15), (W1, W2, W3) = (18, 15, 10)
가능한 해 | ∑WiXi | ∑PiXi | - |
---|---|---|---|
(1/2, 1/3, 1/4) | 16.5 | 24.25 | 일정 비율로 선택, 무게 최대치 충족 X |
(1, 2/15, 0) | 20 | 28.2 | 이익이 큰 것부터 선택, 최적 해 아님 |
(0, 1, 1/2) | 20 | 31.5 | 단위무게당 얻는 이익 고려, 최적 해 |
단위 무게당 얻는 이익 ( = Pi/Wi)
pseudo code
Greedy_Knapsack(float P[], float W[], float X[], float M, int n)
/*P와 W는 P[i]/W[i]에 의하여 내림차순으로 정렬되어 있음*/
{ float cu;
int i;
for(i = 1; i <= n; i++) {X[i] = 0};
cu = M; i = 1;
while((W[i] <= cu) && (i <= n))
{ X[i] = 1;
cu = cu - W[i]; // 남은 무게
i += 1;
}
if (i <= n)
X[i] = cu/W[i] // 쪼개서 넣기
}
배낭 문제에서 Xi를 0 혹은 1로 제한할 경우 (물건을 넣는 경우, 안 넣는 경우 단 두 가지만 존재) -> Greedy_Knapsack은 최적 해를 항상 구하는 것은 아니다. 이 문제는 NP-Complete이다.
ex. n = 3, M = 50, (P1, P2, P3) = (60, 100, 120), (W1, W2, W3) = (10, 20, 30)
x : 1, 2, ..., i, ..., n
f(i, X) : (1, 2, ..., i) 물건들 중 넣든, 넣지 않든 최대 용량
목적 함수의 해 : 가방에 넣을 수 있는 최대 이득
- i를 Knapsack에 넣는 경우 : Pi, Wi를 제외한 나머지
- X - Wi (1, 2, ..., i-1) => Pi + f(i-1, X-Wi) (Wi ≤ X)
- i를 Knapsack에 넣지 않는 경우 => f(i-1, X)
f(i, X) = max{Pi + f(i-1, X-Wi), f(i-1, X)}
f(n,m) 일 때 O(nm)만큼의 시간 복잡도를 갖는다.
Polynomial time Algorithm 처럼 보이나 m이 만약 10^9이면, 전체 수행시간이 엄청나게 증가함을 알 수 있다.
(Nondeterministic Polynomial)
문제의 종류는 크게 두 가지로 나누어 생각할 수 있다.
현실적인 시간은 무엇을 의미하는가? (시간 복잡도의 측면)
비다항식 시간 (Polynomial time Algorithm으로 해결 안됨)