Skip to main content

MST

BOJ 31055 A Graph Problem

·57 words·1 min
πŸ“ 문제 정보 # 링크: https://www.acmicpc.net/problem/31055 λ²ˆμ—­ 문제 λ²ˆμ—­ # BessieλŠ” μˆ˜ν•™ 지식을 ν–₯μƒμ‹œν‚€κΈ° μœ„ν•΄ κ·Έλž˜ν”„ 이둠 κ°•μ’Œλ₯Ό μˆ˜κ°•ν•˜κ³  μžˆλŠ”λ°, λ‹€μŒ λ¬Έμ œμ—μ„œ λ§‰ν˜”μŠ΅λ‹ˆλ‹€. κ·Έλ…€λ₯Ό λ„μ™€μ£Όμ„Έμš”! μ—°κ²°λœ 무방ν–₯ κ·Έλž˜ν”„κ°€ μ£Όμ–΄μ§‘λ‹ˆλ‹€. 정점은 $1\dots N$으둜, 간선은 $1\dots M$으둜 λΌλ²¨λ§λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€ ($2\le N\le 2\cdot 10^5$, $N-1\le M\le 4\cdot 10^5$). κ·Έλž˜ν”„μ˜ 각 정점 $v$에 λŒ€ν•΄ λ‹€μŒ 과정을 μˆ˜ν–‰ν•©λ‹ˆλ‹€:

BOJ 4792 λ ˆλ“œ 블루 μŠ€νŒ¨λ‹ 트리

·327 words·2 mins
πŸ“ 문제 정보 # 링크: https://www.acmicpc.net/problem/4792 🧐 κ΄€μ°° 및 μ ‘κ·Ό # νŒŒλž€μƒ‰ 간선을 $k$개, 빨간색 간선을 $(N-1) - k$개 μ΄μš©ν•΄μ„œ MSTλ₯Ό μ§œμ•Όν•˜λŠ”λ°.. 일단 νŒŒλž€μƒ‰ κ°„μ„  $k$개λ₯Ό κ²°μ •ν•˜λ©΄ 빨간색은 κ·Έλƒ₯ 유파λ₯Ό 닀해버리면 λ˜λ‹ˆκΉŒ, νŒŒλž€μƒ‰ 간선을 잘 κ³ λ₯΄λŠ”κ²Œ μ€‘μš”ν•˜λ‹€. λ‚˜μ΄λΈŒν•˜κ²Œ ν•œλ‹€λ©΄ $\binom{\binom{N}{2}}{k}$인가? κ°„μ„  κ°œμˆ˜λŠ” κ·Έλ ‡λ‹€ 쳐도, $k$개λ₯Ό κ³ λ₯΄λŠ”κ²Œ λ„ˆλ¬΄ 큰디… μž‘μ€ λ¬Έμ œλΆ€ν„° 차근히 ν’€μ–΄λ³΄μž. $k = 0$ 이라면 λͺ¨λ“  κ°„μ„ λ“€λ‘œ μŠ€νŒ¨λ‹νŠΈλ¦¬κ°€ λ§Œλ“€μ–΄μ§€λŠ”μ§€ ν™•μΈν•˜λŠ” 문제둜 바뀐닀. $k = 1$ ![[Drawing 2026-01-30 19.56.46.excalidraw.png]] μœ„μ™€ 같은 κ·Έλž˜ν”„κ°€ μžˆμ—ˆλ‹€κ³  μƒκ°ν•˜μž. νŒŒλž€ κ°„μ„  1개λ₯Ό $1 - 2$ 같은걸 골라버리면 λΆˆκ°€λŠ₯ν•΄μ§€λŠ” λ¬Έμ œκ°€ 생긴닀. 잘 골라야 ν•œλ‹€. 음.. λΉ¨κ°„μƒ‰μœΌλ‘œ 미리 λ‹€ 합쳐놓고, λ‚˜λ¨Έμ§€λ₯Ό μ—°κ²°ν•  개수 μ΄μƒμ˜ νŒŒλž€κ°„μ„ μ€ ν•„μš”ν•œκ±° 같은데.. 그런데, 이미 MSTκ°€ 잘 μžˆλ‹€λ©΄, λΉ¨κ°„ 간선을 νŒŒλž€ κ°„μ„ μœΌλ‘œ λŒ€μ²΄ν•˜λŠ”κ²Œ κ½€ μžμœ λ‘œμš΄κ°€? μ΄κ²ƒλ§Œ 되면 큰 λ¬Έμ œκ°€ μ—†λŠ”λ°? $k > 1$ ![[Drawing 2026-01-30 20.04.04.excalidraw.png]] 주황색이 이미 λ§Œλ“€μ–΄μ§„ MST, λ‚˜λ¨Έμ§€λ₯Ό 남은 간선이라고 ν•˜μž. μ–΄λ–€ νŒŒλž€μƒ‰ 간선을 ν•˜λ‚˜ μ“°κ³ μ‹ΆμœΌλ©΄, 두 μ •μ μœΌλ‘œ κ°€λŠ” κ²½λ‘œμ— μžˆλŠ” 빨간색을 λŠμ–΄λ²„λ¦¬κ³  νŒŒλž€μƒ‰μœΌλ‘œ μƒˆλ‘œ μ—°κ²°ν•˜λ©΄ λœλ‹€! 이게 μ•ˆλ˜λŠ” κ²½μš°λŠ” 이미 κ·Έ 두 μ •μ μœΌλ‘œ κ°€λŠ” κ²½λ‘œκ°€ λ‹€ νŒŒλž€μƒ‰ κ°„μ„ λ§ŒμœΌλ‘œ μ—°κ²°λœ 경우인데.. μ•„ν•˜, 뢄리집합을 ν•˜λ‚˜ 더 κ΄€λ¦¬ν•˜λŠ”κ±Έλ‘œ μ‰½κ²Œ ν’€ 수 μžˆλŠ” 것 κ°™λ‹€. πŸ’» 풀이 # μ½”λ“œ (C++): void solve(){ while(1){ int N, M, K; cin >> N >> M >> K; if(N + M + K == 0) break; vector<pii> Redges, Bedges; rep(i, 0, M){ char color; cin >> color; int u, v; cin >> u >> v; u--; v--; if(color == 'R') Redges.push_back({u, v}); else Bedges.push_back({u, v}); } UnionFind UF(N), BUF(N); // 일단 νŒŒλž€μƒ‰ 간선을 μ΅œμ†Œλ‘œ μ“Έλ•Œ λ˜λŠ”μ§€ 확인 int cnt = 0; for(auto [u, v]: Redges) UF.merge(u, v); for(auto [u, v]: Bedges) if(UF.merge(u, v)){ cnt++; BUF.merge(u, v); } if(cnt > K){ cout << 0 << '\n'; continue; } // λΉ¨κ°„ 간선을 ν•˜λ‚˜ν•˜λ‚˜ νŒŒλž€μƒ‰μœΌλ‘œ λ°”κΎΈκΈ° for(auto [u, v]: Bedges) if(BUF.merge(u, v)) cnt++; if(cnt < K){ cout << 0 << '\n'; continue; } cout << 1 << '\n'; } } πŸ”’ κ΅¬ν˜„ μ½”λ“œ 잠금

BOJ 2887 ν–‰μ„± 터널

·196 words·1 min
πŸ“ 문제 정보 # 링크: https://www.acmicpc.net/problem/2887 🧐 κ΄€μ°° 및 μ ‘κ·Ό # λˆ„κ°€λ΄λ„ MSTλ₯Ό μ§œμ•Όν•˜λŠ”κ±°κ°™μ€λ°.. ν–‰μ„± λ‘κ°œμ— λŒ€ν•΄ λͺ¨λ‘ μƒκ°ν•˜λ©΄ κ°„μ„ μ˜ κ°œμˆ˜κ°€ $N^2$κ°œκ°€ λœλ‹€… 그런데, 생각해보면 λ§Œμ•½ ν–‰μ„± $A, B, C$κ°€ 있고, μ„Έκ°œ λͺ¨λ‘ $x$λ₯Ό κΈ°μ€€μœΌλ‘œ μ—°κ²°ν–ˆλ‹€κ³  ν•˜μž. $x_A < x_B < x_C$라면, $x_A$와 $x_C$의 관계λ₯Ό μ‹ κ²½ μ“Έ ν•„μš”κ°€ μžˆμ„κΉŒ? μ—†λ‹€!! λ”°λΌμ„œ, $x, y, z$ 각각에 λŒ€ν•΄ μ •λ ¬ν•œ κ°„μ„  $3N$κ°œμ •λ„λ₯Ό μ΄μš©ν•΄μ„œ MSTλ₯Ό 짜자. πŸ’» 풀이 # μ½”λ“œ (C++): void solve(){ int N; cin >> N; vector<array<ll, 4>> planets; rep(i, 0, N){ int x, y, z; cin >> x >> y >> z; planets.push_back({x, y, z, i}); } vector<array<ll, 3>> edges; sort(all(planets), [](auto &a, auto &b){ return a[0] < b[0]; }); rep(i, 0, N-1) edges.push_back({abs(planets[i][0]-planets[i+1][0]), planets[i][3], planets[i+1][3]}); sort(all(planets), [](auto &a, auto &b){ return a[1] < b[1]; }); rep(i, 0, N-1) edges.push_back({abs(planets[i][1]-planets[i+1][1]), planets[i][3], planets[i+1][3]}); sort(all(planets), [](auto &a, auto &b){ return a[2] < b[2]; }); rep(i, 0, N-1) edges.push_back({abs(planets[i][2]-planets[i+1][2]), planets[i][3], planets[i+1][3]}); sort(all(edges)); UF.init(N); ll ans = 0; for(auto [w, u, v]: edges) if(UF.merge(u, v)) ans += w; cout << ans << '\n'; } πŸ”’ κ΅¬ν˜„ μ½”λ“œ 잠금

BOJ 1647 λ„μ‹œ λΆ„ν•  κ³„νš

·152 words·1 min
πŸ“ 문제 정보 # 링크: https://www.acmicpc.net/problem/1647 🧐 κ΄€μ°° 및 μ ‘κ·Ό # μ§‘ (정점)κ³Ό κΈΈ (κ°„μ„ )이 μžˆλ‹€. λ§ˆμ„ λ‘κ°œλ‘œ λΆ„λ¦¬ν•΄μ•Όν•œλ‹€. 이 λ•Œ, κ°„μ„ μ˜ κ°€μ€‘μΉ˜μ˜ 합을 μ΅œμ†Œν™”ν•΄μ•Όν•œλ‹€. 이미 두 집이 ν•œ λ§ˆμ„ μ•ˆμ— μžˆλ‹€λ©΄, λ‘˜μ΄ μ—°κ²°ν•  ν•„μš”κ°€ μ—†λ‹€. 이미 λ‹€λ₯Έ 우회둜둜 갈 수 있기 λ•Œλ¬Έ μ—°κ²°ν•˜λ˜ 도쀑 λ§ˆμ„μ΄ λ‘κ°œκ°€ λ‚¨μ•˜λ‹€λ©΄ 끝내면 λœλ‹€. 크루슀칼 μ•Œκ³ λ¦¬μ¦˜μœΌλ‘œ 덩어리가 λ‘κ°œκ°€ λ‚¨μ„λ•ŒκΉŒμ§€ λ°˜λ³΅ν•˜λ©΄ λ˜κ² λ‹€. πŸ’» 풀이 # μ½”λ“œ (C++): void solve(){ int N, M; cin >> N >> M; vector<tuple<int, int, int>> edges; // weight, u, v rep(i, 0, M){ int u, v, w; cin >> u >> v >> w; edges.emplace_back(w, u, v); } UF.init(N+1); sort(all(edges)); int ans = 0; for(auto &[w, u, v]: edges){ if(UF.group == 3) break; if(UF.merge(u, v)) ans += w; } cout << ans << "\n"; } πŸ”’ κ΅¬ν˜„ μ½”λ“œ 잠금