Skip to content

Commit 83a4305

Browse files
committed
Quartz sync: Oct 21, 2025, 2:44 PM
1 parent 5defdd0 commit 83a4305

File tree

3 files changed

+125
-41
lines changed

3 files changed

+125
-41
lines changed

content/Computer Science/1 Foundations & Theory/Algorithms/Traveling Salesman Problem.md

Lines changed: 107 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,61 +3,128 @@ description:
33
aliases:
44
- tsp
55
created: 2025-05-18
6-
modified: 2025-07-04
6+
modified: 2025-10-21
77
---
8+
89
- TSP is a touchstone for many general heuristics devised for combinatorial optimization such as [genetic algorithms](https://en.wikipedia.org/wiki/Genetic_algorithm "Genetic algorithm")[simulated annealing](https://en.wikipedia.org/wiki/Simulated_annealing "Simulated annealing")[tabu search](https://en.wikipedia.org/wiki/Tabu_search "Tabu search")[ant colony optimization](https://en.wikipedia.org/wiki/Ant_colony_optimization "Ant colony optimization")[river formation dynamics](https://en.wikipedia.org/w/index.php?title=River_formation_dynamics&action=edit&redlink=1 "River formation dynamics (page does not exist)") (see [swarm intelligence](https://en.wikipedia.org/wiki/Swarm_intelligence "Swarm intelligence")), and the [cross entropy method](https://en.wikipedia.org/wiki/Cross_entropy_method "Cross entropy method").
910
- DP (recursive)
1011
- DP + Bit mask
11-
-  Held-Karp 알고리즘
12+
- Held-Karp 알고리즘
1213
- `dp[current][visited]`
1314
- 현재 도시가 current이고, visited는 지금까지 방문한 도시의 집합
1415
- visited는 비트마스크 (0 ~ 2ⁿ - 1)로 표현
1516
- ```peusudo
16-
function tsp(current, visited):
17-
// 모든 조합이라는 것은 다 돌았다는 뜻
18-
if visited == all_visited_mask((1 << N) - 1):
19-
// 마지막에서 처음으로 가는 비용이 있다는 것은 돌아 갈 수 있다는 말
20-
if cost[current][start] > 0:
21-
return cost[current][start] // 돌아가는 비용
17+
function TSP(u, mask):
18+
# 의미: 현재 도시가 u, 이미 방문한 집합이 mask일 때
19+
# 남은 도시들을 모두 방문하고 start로 귀환하는 "최소 추가 비용"
20+
21+
if mask == FULL:
22+
# 모든 도시를 방문했다면 start로 귀환해야 함
23+
if cost[u][start] < INF:
24+
return cost[u][start]
2225
else:
23-
// 돌아가지 못함으로
24-
return INF // 못 돌아감
26+
return INF
2527
26-
// 이미 구한 값이 있으면 얼리 리턴 (not initial value ex: -1)
27-
if dp[current][visited] is already computed:
28-
return dp[current][visited]
28+
if dp[u][mask] != UNKNOWN:
29+
return dp[u][mask]
2930
30-
dp[current][visited] = INF
31+
best = INF
32+
best_next = NONE
3133
32-
// 모든 도시에 대해서
33-
for next in 0 to N-1:
34-
// 조합에 없는 도시만 비트마스크로 추출, 거리가 있다면 dp 없데이트
35-
if city 'next' is not visited and cost[current][next] > 0:
36-
dp[current][visited] = min(
37-
dp[current][visited],
38-
tsp(next, visited | (1 << next)) + cost[current][next]
39-
)
34+
for v in 0 .. N-1:
35+
if (mask has bit v) continue # 이미 방문된 도시는 스킵
36+
if cost[u][v] == INF continue # 간선 없음
4037
41-
return dp[current][visited]
38+
cand = cost[u][v] + TSP(v, mask ∪ {v})
39+
if cand < best:
40+
best = cand
41+
best_next = v
42+
43+
dp[u][mask] = best
44+
parent[u][mask] = best_next # 경로 복원을 원할 경우
45+
return best
4246
- 전이 공식
4347
- `mask`: 방문한 도시 집합
4448
- `last`: 마지막 방문 도시
4549
- `dp[mask][last]` = mask를 돌고 last에서 끝날 때 최소 비용
50+
- 출발 지점이 `0`인 이유
51+
- 사이클의 회전 불변성 덕분에 출발점을 하나로 고정
52+
- 다음 사이클의 비용은 같다
53+
- `0 → 1 → 2 → 3 → 0`
54+
- `1 → 2 → 3 → 0 → 1`
4655
- ```cpp
47-
dp[1<<0][0] = 0;
48-
for(mask = 0 ; mask < 1<<N; mask++){
49-
for(last = 0; last < N; last++){
50-
if(!(mask & 1 << last)) continue; // last가 이미 있다면 패스
51-
52-
for(next = 0; next < N; next++){
53-
if(mask & 1 << next) continue; // next가 이미 있다면 패스
54-
55-
newMask = mask | (1<<next);
56-
57-
dp[newMask][next] = min(
58-
dp[newMask][next],
59-
dp[mask][last] + dist[last][next]
60-
);
61-
}
62-
}
63-
}
56+
#include <bits/stdc++.h>
57+
using namespace std;
58+
59+
static constexpr int INF = 1e9;
60+
61+
int main() {
62+
ios::sync_with_stdio(false);
63+
cin.tie(nullptr);
64+
65+
int n;
66+
cin >> n;
67+
68+
vector<vector<int>> cost(n, vector<int>(n, 0));
69+
70+
// 비용 입력
71+
for (int i = 0; i < n; ++i)
72+
for (int j = 0; j < n; ++j)
73+
cin >> cost[i][j];
74+
75+
// 자기 자신 위치 제외, 비용이 0이면 INF로 치환 (반복문안에서 조건문으로 비교는 속도 저하, 실수 유발 가능)
76+
for (int i = 0; i < n; ++i) {
77+
for (int j = 0; j < n; ++j) {
78+
if (i == j) continue;
79+
if (cost[i][j] == 0) cost[i][j] = INF;
80+
}
81+
}
82+
83+
// start 0으로 고정 및 start 포함 안하는 mask 패싱하기
84+
// 헤밀턴 경로는 순환이기에 0으로 고정하고 문제를 접근
85+
const int start = 0;
86+
const int FULL = 1 << n; // 전체 집합(마스크) 개수
87+
88+
vector<vector<int>> dp(FULL, vector<int>(n, INF));
89+
//dp[현재까지 방문한 집합][마지막 지점이 u일때]의 전체 비용
90+
//dp[fullmask][u] + cost[v][start] -> 전체를 순회한 비용
91+
dp[1 << start][start] = 0;
92+
93+
for (int mask = 0; mask < FULL; ++mask) {
94+
// 시작지점 없는 마스크는 패스
95+
if ((mask & (1 << start)) == 0) continue;
96+
97+
for (int u = 0; u < n; ++u) {
98+
// 마스크중 특정 비트 선택(해당 지점을 마지막으로 하기위해)
99+
if ((mask & (1 << u)) == 0) continue;
100+
101+
int cur = dp[mask][u];
102+
if (cur >= INF) continue;
103+
104+
// 다음 마스크 찾기
105+
for (int v = 0; v < n; ++v) {
106+
107+
// 이미 있는 비트 패스
108+
if (mask & (1 << v)) continue;
109+
// 비용이 없으면 도달 불가능 패스
110+
if (cost[u][v] >= INF) continue;
111+
112+
// [새로운 마스크][마지막 지점]의 경우 비용 갱신
113+
int next_mask = mask | (1 << v);
114+
dp[next_mask][v] = min(dp[next_mask][v], cur + cost[u][v]);
115+
}
116+
}
117+
}
118+
119+
int answer = INF;
120+
int full_mask = FULL - 1;
121+
for (int u = 0; u < n; ++u) {
122+
if (dp[full_mask][u] >= INF) continue;
123+
if (cost[u][start] >= INF) continue;
124+
answer = min(answer, dp[full_mask][u] + cost[u][start]);
125+
}
126+
127+
cout << answer;
128+
129+
return 0;
130+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
description:
3+
aliases:
4+
created: 2025-10-13
5+
modified: 2025-10-13
6+
---
7+
8+
- [containerd](https://containerd.io/)
9+
- [Podman](https://podman.io/)

content/index.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,21 @@ aliases:
33
description: This blog is an excerpt from my Obsidian notes
44
title: Hello Again!
55
created: 2025-05-18
6-
modified: 2025-09-01
6+
modified: 2025-10-12
77
comments: "true"
88
---
99

1010
<!--
1111
![Typing SVG](https://readme-typing-svg.herokuapp.com?font=Fira&weight=500&size=42&duration=2468&pause=4000&width=600&height=70&lines=Hello%2C+Again!)
1212
-->
13+
<!-- memo
14+
- 파일 맨 앞에 이름이 '-'로 시작은 index 파일용 이름임 (자동으로 quartz 인덱스 파일이 됨)
15+
- 같은 폴더에 '-'로 시작하는 파일이 여러개라면 1개만 인덱스가 됨
16+
- 인덱스용 파일은 '-'로 지정하기
17+
- 그외의 파일은 우선순위를 위해서 다른 캐릭터 사용하기
18+
- '_'은 파일 우선순위를 위해 사용하는 나만의 컨벤션
19+
-->
20+
1321
![[Lqp2z3I.gif]]
1422

1523
Hi, I’m Yoma. This blog is my digital garden - mi casa es su casa.

0 commit comments

Comments
 (0)