do {
우선 가장 좋아보이는 선택을 한다.
} until 문제의 끝까지
그리디 알고리즘은 결정을 해야 할 때마다 그 순간에 가장 좋다고 생각되는 것을 해답으로 선택함으로써 최종적인 해답에 도달한다.
그 순간의 선택은 그 당시(local)에는 최적이다. 그러나 최적이라고 생각했던 해답들을 모아서 최종적인(global) 해답을 만들었다고 해서, 그 해답이 궁극적으로 최적이라는 보장이 없다.
따라서 그리디 알고리즘은 항상 최적의 해답을 주는지를 반드시 검증해야 한다.
: 현재 상태에서 가장 좋으리라고 생각되는 (greedy criterion) 해답을 찾아서 해답 모음 (solution set)에 포함시킨다.
: 새로 얻은 해답 모음이 적절한지를 결정한다.
: 새로 얻은 해답모음이 최적의 해인지를 결정한다.
while (there are more coins and the instance is not solved) {
Grab the largest remaining coin; // 선정과정
if ( adding the coin makes the change exceed the amount owed){
reject the coin; // 적정성 점검
}
else
add the coin to the change;
if ( the total value of the change equals the amount owed )
the instance is solved; // 해답 점검
}
: 현재 상태에서의 최적만을 찾기 때문에, 비교하는 현재 노드의 자식노드를 고려하지 못함. 따라서 최종적으로 최적해가 아닐 가능성이 있다.
: 동전의 액면이
500원, 100원, 50원, 10원, 5원, 1원 으로 구성되어 있다.
하지만, 액면이 바로 아래 액면의 배수가 되지 않으면, 그리디 알고리즘으로 최적해가 보장되지 않게 된다.
: 동전의 액면이
500원, 400원, 100원, 75원, 50원 으로 구성되어 있다.
: 좌측은 연결된 가중치 비방향 그래프, 우측은 Spanning Tree의 예
최소의 가중치를 가진 부분그래프는 반드시 트리가 되어야 한다. 왜냐하면, 트리가 아니라면, 분명히 순환경로(Cycle)가 있을 것이고, 그렇게 되면 순환경로 상의 한 이음선을 제거하면 더 작은 비용의 신장트리가 되기 때문이다.
관찰 : 모든 신장트리가 최소비용 신장트리는 아니다.
: 좌측은 연결되 가중치 비방향 그래프, 우측은 Minimum Spanning Tree의 예
problem : 비방향성 그래프 G=(V,E)가 주어졌을 때, F⊆E를 만족하면서, (V,F)가 G의 최소비용신장트리(MST)가 되는 F를 찾는 문제.
Algorithm
F = ∅
while (the instance is not solved) {
select an edge according to some locally # selection procedure
optimal consideration;
if (adding the edge to F dose not create a cycle)
add it; # feasibility procedure
if ( T = (V,F) is a spanning tree) # solution check
the instance is solved;
}
F = ∅; # initialize set of edges to empty
Y = {v1}; # initialize set of vertices to
# contain only the first one
while ( the instance is not solved ) {
select a vertex in V-Y that is nearest to Y;
# selection procedure and
# feasibility check
add the vertex to Y;
add the edge to F;
if ( Y==V ) # solution check
the istance is solved;
}
예 1)
예 2)
void prim ( int n, const number W[][], set_of_edges& F){
index i, vnear; number min; edge e;
index nearest[2..n]; number distance[2..n]
F=∅;
for ( i=2; i<=n; i++ ){ # 초기화
nearest[i] = 1; # vi에서 가장 가까운 정점을 v1으로 초기화
distance[i] = W[1][i];
}
repeat(n-1 times) { # n-1 개의 정점을 Y에 추가한다
min = "infinite";
for (i=2; i<=n; i++) # 각 정점에 대해서
if ( 0<=distance[i]<=min){ # distance[i]를 검사하여
min = distance[i]; # 가장 가까이 있는 vnear을
vnear = i; # 찾는다.
}
e = edge connecting vertices indexed by vnear and nearest[vnear];
add e to F;
distance[vnear] = -1; # 찾은 노드를 Y에 추가한다.
for ( i=2; i<=n; i++ )
if (W[i][vnear] < distance[i]){
distance[i] = W[i][vnear]; # Y에 없는 각 노드에 대해서
nearest[i] = vnear; # distance[i]를 갱신한다.
}
}
}
F = ∅ # initialize set of edges
# to empty
create disjoint subsets of V, one for each
vertex and comtaining only that vertex;
sort the edges in E in nondecreasing order;
While ( the instance is not solved ) {
select next edge; # selection procedure
if ( the edge connects 2 vertices in disjoint subsets ) {
# feasibility check
merge the subsets;
add the edge to F;
}
if ( all the subsets are merged ) # solution check
the instnace is solved;
}
예 1)
예 2)
void kruskal (int n, int m. set_of_edges E, set_of_edges& F) {
index i,j;
set_pointer p, q;
edge e;
Sort the m edges in E by weight in nondecreasing order;
F = ∅;
initial(n); # n개의 서로소 부분집합을 초기화
# (하나의 부분집합에 1에서 n사이의 인덱스가 정확히 하나 포함됨)
While (number of edges in F is less than n-1) {
e = edges with least weight not yet considered;
i,j = indices of vertices connected by e;
p = find(i); # 인덱스 i가 포함된 집합의 포인터 p를 넘겨줌
q = find(j);
if ( !equal (p,q) { # p와 q가 같은 집합을 가리키면 true를 넘겨줌
merge(p,q); # 두 개의 집합을 가리키는 p와 q를 합병
add e to F;
}
}
}
F = 0;
Y = {v1};
While ( the instance is not solved )
# selection procedure
select a vertex v from V-Y, that has a shortest path
# and feasibility check
from v1, using only vertices in Y as intermediate;
add the new vertex v to Y;
add the edge (on the shortest) that touches v to F;
# solution check
if( Y == V ) #
the instance is solved;
예 1)
예 2)
void dijkstra ( int n, const number W[][], set_of_edges& F ) {
index i, vnear; edge e;
index touch[2..n]; number length[2..n];
F=∅;
for (i=2; i<=n; i++) { # For all vertices, initialize v1 to be the last
touch[i] = 1; # vertex on the current shortest path from v1,
length[i] = W[1][i]; # and initialize length of that path to be the
} # weight on the edge from v1
repeat(n-1 times) { # Add all n-1 vertices to Y.
min = "infinite";
for ( i=2; i<=n; i++ ) # Check each vertex for having shortest path.
if ( 0 <= length[i] <= min ){
min = length[i];
vnear = i;
}
e = edge from vertex indexed by touch[vnear]
to vertex indexed by vnear;
add e to F;
for ( i=2; i<=n; i++ )
if ( length[vnear] + W[vnear][i] < length[i]) {
length[i] = length[vnear] + W[vnear][i];
touch[i] = vnear; # For each vertex not in Y, update its shortest
} # path. Add vertex indexed by vnear to Y.
length[vnear] = -1;
}
}