
한 순간 최선(탐욕) 선택이 전체 최적해로 이어진다고 가정하고 푸는 방법.
성립 조건:
1) 정렬 기준 정의 (예: 끝나는 시간, 비용/가치 비율 등)
2) 조건을 만족하는 한에서 현재 최선의 후보를 고른다
3) 선택으로 인한 상태(용량/시간/집합)를 갱신한다
dist[] = INF; dist[src] = 0
pq = min-heap of (dist, node)
push (0, src)
while pq not empty:
(d, u) = pop
if d > dist[u]: continue // stale entry skip
for (v, w) in adj[u]:
if dist[v] > dist[u] + w:
dist[v] = dist[u] + w
push (dist[v], v)
class Edge { int to, w; Edge(int t, int w){ this.to=t; this.w=w; } }
List<Edge>[] g;
int[] d; boolean[] vis;
void dijkstra(int s){
Arrays.fill(d, Integer.MAX_VALUE);
d[s] = 0;
PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
pq.offer(new int[]{0, s});
while(!pq.isEmpty()){
int[] cur = pq.poll();
int dist = cur[0], u = cur[1];
if(dist != d[u]) continue;
for(Edge e : g[u]){
if(d[e.to] > d[u] + e.w){
d[e.to] = d[u] + e.w;
pq.offer(new int[]{d[e.to], e.to});
}
}
}
}
INF의사코드
sort edges by weight asc
init DisjointSet (parent/rank)
for each edge (u, v, w) in edges:
if find(u) != find(v):
union(u, v)
take edge (u, v, w)
복잡도: 정렬 O(E log E) + 유니온파인드 거의 상수 → O(E log E)
의사코드
pick any start s
visited[s] = true; push all (w, s->v) into pq
while pq not empty and picked < V-1:
(w, u->v) = pop min
if visited[v] continue
visited[v] = true; take (u, v, w)
push all (w', v->x) where !visited[x]
복잡도: 인접 리스트 + 힙 O(E log V), 인접 행렬 + 선형스캔 O(V²)
class DSU {
int[] p, r;
DSU(int n){ p = new int[n]; r = new int[n]; for(int i=0;i<n;i++) p[i]=i; }
int find(int x){ return p[x]==x ? x : (p[x]=find(p[x])); }
boolean union(int a, int b){
a = find(a); b = find(b);
if(a==b) return false;
if(r[a] < r[b]) { int t=a; a=b; b=t; }
p[b] = a;
if(r[a]==r[b]) r[a]++;
return true;
}
}
| 주제 | 목적 | 전제/조건 | 핵심 아이디어 | 전형 복잡도 |
|---|---|---|---|---|
| Greedy | 전역 최적 근사/도출 | 탐욕 선택 + 최적 부분 구조 | “현재 최선”을 반복 선택 | 보통 정렬 O(n log n) + O(n) |
| Dijkstra | 단일 시작 최단거리 | 비음수 간선 | 가장 가까운 정점부터 확정(완화) | O((V+E) log V) |
| MST–Kruskal | 모든 정점 연결 최소 비용 | 무방향·연결 | 간선 정렬 + 유니온파인드 | O(E log E) |
| MST–Prim | 모든 정점 연결 최소 비용 | 무방향·연결 | PQ로 트리 바깥 최소 간선 추가 | O(E log V) |