Skip to main content

Algorithm

BOJ 1734 ꡐ톡 체계

·405 words·2 mins
πŸ“ 문제 정보 # 링크: https://www.acmicpc.net/problem/1734 🧐 κ΄€μ°° 및 μ ‘κ·Ό # 무ν–₯ κ·Έλž˜ν”„ $G = (V, E)$κ°€ μ£Όμ–΄μ§„λ‹€. μ—¬κΈ°μ„œ 두가지 쿼리가 μ£Όμ–΄μ§„λ‹€. κ°„μ„  $e \in E$ ν•˜λ‚˜λ₯Ό 없앴을 λ•Œ, 정점 $A, B$의 μ—°κ²°μ„± νŒμ • 정점 $v \in V$ ν•˜λ‚˜λ₯Ό 없앴을 λ•Œ, 정점 $A, B$의 μ—°κ²°μ„± νŒμ • 각각 μ‚΄νŽ΄λ³΄μž. λ¨Όμ €, λ¬Έμ œμ‘°κ±΄μ— μ˜ν•΄ μ»΄ν¬λ„ŒνŠΈλŠ” ν•˜λ‚˜μ΄λ―€λ‘œ A, BλŠ” 기본적으둜 μ—°κ²°λ˜μ–΄μžˆλ‹€κ³  νŒλ‹¨ν•˜μž.

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"; } πŸ”’ κ΅¬ν˜„ μ½”λ“œ 잠금

BOJ 10775 곡항

·145 words·1 min
πŸ“ 문제 정보 # 링크: https://www.acmicpc.net/problem/10775 🧐 κ΄€μ°° 및 μ ‘κ·Ό # 1번 κ²Œμ΄νŠΈκ°€ 제일 μ“°κΈ° 쒋아보인닀. κ·ΈλŸ¬λ―€λ‘œ 1번 게이트λ₯Ό μ•„λ‚€λ‹€κ³  μƒκ°ν•˜λ©΄, λͺ¨λ“  λΉ„ν–‰κΈ°λ₯Ό λ„ν‚Ήμ‹œν‚¬λ•Œ 갈 수 μžˆλŠ” μ΅œλŒ“κ°’μœΌλ‘œ λ„ν‚Ήμ‹œν‚€λ©΄ λ˜λŠ” 것 κ°™λ‹€. 이λ₯Ό λ‚˜μ΄λΈŒν•˜κ²Œ κ΅¬ν˜„ν•˜λ©΄ ν•œλ²ˆλ‹Ή $O(G)$κ°€ 걸릴 것이닀. 100000 100000 100000 100000 100000 ... κ³Ό 같은 ν…ŒμŠ€νŠΈμΌ€μ΄μŠ€λ₯Ό 생각해보면 λœλ‹€. λ”°λΌμ„œ $\text{calc}(g_i) = g_i$ 보닀 μž‘κ±°λ‚˜ 같은 μ‚΄μ•„μžˆλŠ” 게이트의 μ΅œλŒ“κ°’μ„ λΉ λ₯΄κ²Œ 찾으면 λœλ‹€. μ΄λŠ” μœ λ‹ˆμ˜¨νŒŒμΈλ“œλ‘œ λΉ λ₯΄κ²Œ μˆ˜ν–‰ κ°€λŠ₯ν•˜λ‹€! mergeν• λ•Œ μžμ‹ λ³΄λ‹€ μž‘μ€ 값을 κ°€λ¦¬ν‚€κ²Œ ν•˜μž. πŸ’» 풀이 # μ½”λ“œ (C++): void solve(){ int G, P; cin >> G >> P; UF.init(G+1); int ans = 0; while(P--){ int g; cin >> g; int rt = UF.find(g); if(rt == 0) break; UF.merge(rt, rt-1); ans++; } cout << ans << "\n"; } πŸ”’ κ΅¬ν˜„ μ½”λ“œ 잠금

BOJ 1043 거짓말

·161 words·1 min
πŸ“ 문제 정보 # 링크: https://www.acmicpc.net/problem/1043 🧐 κ΄€μ°° 및 μ ‘κ·Ό # μ§€λ―Όμ΄λŠ” λͺ¨λ“  νŒŒν‹°μ— μ°Έμ—¬ν•΄μ•Όν•˜λ―€λ‘œ, 진싀을 μ•„λŠ” μ‚¬λžŒμ΄ μžˆλŠ” νŒŒν‹°μ˜ λͺ¨λ“  μ‚¬λžŒμ€ 진싀을 μ•Œκ²Œ λœλ‹€. λͺ¨λ“  νŒŒν‹°μ— λŒ€ν•΄ 진싀을 μ•Œκ²Œ 된 μ‚¬λžŒμ„ ν™•μΈν•œ ν›„, 진싀을 μ•„λŠ”μ‚¬λžŒμ΄ μ—†λŠ” νŒŒν‹°λ“€μ˜ 수λ₯Ό μ„Έλ©΄ λœλ‹€. μœ λ‹ˆμ˜¨ νŒŒμΈλ“œ, 뢄리 μ§‘ν•©μœΌλ‘œ ν•΄κ²°ν•˜μž. πŸ’» 풀이 # μ½”λ“œ (C++): void solve(){ int N, M; cin >> N >> M; vector<vector<int>> parties; UnionFind UF(N+1); // 0은 진싀을 μ•„λŠ” μ‚¬λžŒ int cnt; cin >> cnt; rep(i, 0, cnt){ int a; cin >> a; UF.merge(0, a); } rep(i, 0, M){ cin >> cnt; vector<int> party(cnt); rep(j, 0, cnt) cin >> party[j]; parties.push_back(party); rep(j, 0, cnt-1) UF.merge(party[j], party[j+1]); } int ans = 0; for(auto party: parties){ bool flag = true; for(auto p: party) if(UF.find(p) == 0) flag = false; if(flag) ans++; } cout << ans; } πŸ”’ κ΅¬ν˜„ μ½”λ“œ 잠금

BOJ 4013 ATM

·212 words·1 min
πŸ“ 문제 정보 # 링크: https://www.acmicpc.net/problem/4013 🧐 κ΄€μ°° 및 μ ‘κ·Ό # κ·Έλž˜ν”„κ°€ DAG라면 μœ„μƒμ •λ ¬μ„ ν•˜λ©΄μ„œ DPλ₯Ό μ§„ν–‰ν•  수 μžˆμ„ν…λ°.. 같은 정점을 μ—¬λŸ¬λ²ˆ 듀릴 수 μžˆμœΌλ―€λ‘œ, μ–΄λ–€ 정점이 사이클 μ•ˆμ— λ“€μ–΄μžˆλ‹€λ©΄ ν•΄λ‹Ή 사이클 λ‚΄μ˜ ATM을 λͺ¨λ‘ 듀릴 수 μžˆλ‹€! μ„œλ‘œ 자유둭게 이동 κ°€λŠ₯ν•œ 관계라면 λͺ¨λ‘ 자유둭게 듀릴 수 μžˆμœΌλ―€λ‘œ, 이λ₯Ό SCC둜 λ¬Άμ–΄ DAG둜 λ§Œλ“€μž. πŸ’» 풀이 # μ½”λ“œ (C++): void solve(){ cin >> N >> M; DirectedGraph graph(N+1); rep(i, 0, M){ int u, v; cin >> u >> v; graph.add_edge(u, v); } DirectedGraph dag = graph.getCompressedGraph(); int sz = dag.V; vector<int> val(sz), DP(sz, -1e9), indeg(sz, 0); rep(i, 1, N+1){ int X; cin >> X; val[graph.sccId[i]] += X; } int S, P; cin >> S >> P; S = graph.sccId[S]; DP[S] = val[S]; rep(u, 0, sz) for(auto &v: dag.links[u]) indeg[v]++; queue<int> Q; rep(i, 0, sz) if(indeg[i] == 0) Q.push(i); while(!Q.empty()){ int cur = Q.front(); Q.pop(); for(auto nxt: dag.links[cur]){ DP[nxt] = max(DP[nxt], DP[cur] + val[nxt]); indeg[nxt]--; if(indeg[nxt] == 0) Q.push(nxt); } } int ans = 0; rep(i, 0, P){ int X; cin >> X; X = graph.sccId[X]; ans = max(ans, DP[X]); } cout << ans << '\n'; } πŸ”’ κ΅¬ν˜„ μ½”λ“œ 잠금

BOJ 3648 μ•„μ΄λŒ

·165 words·1 min
πŸ“ 문제 정보 # 링크: https://www.acmicpc.net/problem/3648 🧐 κ΄€μ°° 및 μ ‘κ·Ό # λͺ¨λ“  μ‹¬μ‚¬μœ„μ›μ— λŒ€ν•΄ (and) 각 μ‹¬μ‚¬μœ„μ›λ³„λ‘œ ν‘œ λ‘κ°œμ€‘ ν•˜λ‚˜λ₯Ό λ§Œμ‘±ν•΄μ•Ό ν•œλ‹€. (or) λ”°λΌμ„œ $(A \lor B) \land (C \lor D) \land \cdots$ 의 2-sat 문제둜 λ³€ν™˜ κ°€λŠ₯ν•˜λ‹€! λͺ¨λΈλ§λ§Œ 잘 ν•΄λ³΄μž. κ°€λŠ₯ν•œ λ³€μˆ˜μ˜ 개수 $= 1000 *2 = 2000$ 에 λŒ€ν•΄ $i$ 번 μ°Έκ°€μžκ°€ μ§„μΆœ: $2*i$, μ§„μΆœ μ‹€νŒ¨: $2*i+1$둜 λͺ¨λΈλ§ν•˜μž. 1번 μ°Έκ°€μžμΈ μƒκ·Όμ΄λŠ” 무쑰건 톡과해야 ν•œλ‹€. $\neg x \to x$ λ₯Ό λ§Œμ‘±ν•˜λ©΄ λ˜λ―€λ‘œ, $1 \to 0$을 μΆ”κ°€ν•˜μž. πŸ’» 풀이 # μ½”λ“œ (C++): void solve(){ int N, M; while(cin >> N >> M){ DirectedGraph dg(2*N); rep(i, 0, M){ int u, v; cin >> u >> v; if(u > 0) u = 2*(u-1); else u = 2*(-u-1)+1; if(v > 0) v = 2*(v-1); else v = 2*(-v-1)+1; dg.add_2sat_edge(u, v); } dg.add_2sat_edge(0, 0); cout << (dg.is2SAT() ? "yes\n" : "no\n"); } πŸ”’ κ΅¬ν˜„ μ½”λ“œ 잠금

BOJ 3176 λ„λ‘œ λ„€νŠΈμ›Œν¬

·146 words·1 min
πŸ“ 문제 정보 # 링크: https://www.acmicpc.net/problem/3176 🧐 κ΄€μ°° 및 μ ‘κ·Ό # λ„λ‘œκ°€ N-1개인걸 λ³΄λ‹ˆ 트리겠ꡬ만 μ΄λ•Œ κ²½λ‘œμƒμ—μ„œ κ°€μž₯ 짧은 λ„λ‘œμ˜ 길이와 κ°€μž₯ κΈ΄ λ„λ‘œμ˜ 길이λ₯Ό 좜λ ₯ν•˜λΌλŠ”λ°… HLDλ₯Ό 써도 λ˜μ§€λ§Œ, sparse tableμ—μ„œμ˜ RMQ처리처럼 진행해도 큰 λ¬Έμ œκ°€ μ—†κ² λ‹€. πŸ’» 풀이 # μ½”λ“œ (C++): void solve(){ cin >> N; rep(i, 0, N-1){ int u, v, w; cin >> u >> v >> w; links[u].push_back({v, w}); links[v].push_back({u, w}); } dfs(1, -1, 0); rep(j, 1, 20) rep(i, 1, N+1) if(par[i][j-1]){ par[i][j] = par[par[i][j-1]][j-1]; mnDist[i][j] = min(mnDist[i][j-1], mnDist[par[i][j-1]][j-1]); mxDist[i][j] = max(mxDist[i][j-1], mxDist[par[i][j-1]][j-1]); } int Q; cin >> Q; while(Q--){ int u, v; cin >> u >> v; auto [mn, mx] = calc(u, v); cout << mn << ' ' << mx << '\n'; } } πŸ”’ κ΅¬ν˜„ μ½”λ“œ 잠금

BOJ 1761 μ •μ λ“€μ˜ 거리

·226 words·2 mins
πŸ“ 문제 정보 # 링크: https://www.acmicpc.net/problem/1761 🧐 κ΄€μ°° 및 μ ‘κ·Ό # νŠΈλ¦¬μ—μ„œ, 두 정점 μ‚¬μ΄μ˜ κ²½λ‘œλŠ” μœ μΌν•˜λ‹€. ν•΄λ‹Ή κ²½λ‘œλŠ” 두 μ •μ μ˜ LCAλ₯Ό μ§€λ‚œλ‹€. 두 점 μ‚¬μ΄μ˜ κ±°λ¦¬λŠ” $d(u) + d(v) - 2*d(\text{LCA}(u, v))$둜 계산할 수 μžˆλ‹€. πŸ’» 풀이 # μ½”λ“œ (C++): void dfs(int cur, int _par){ for(auto [nxt, w]: links[cur]){ if(nxt == _par) continue; dist[nxt] = dist[cur] + w; depth[nxt] = depth[cur] + 1; par[nxt][0] = cur; dfs(nxt, cur); } } int LCA(int u, int v){ if(u == v) return u; if(depth[u] < depth[v]) swap(u, v); int diff = depth[u] - depth[v]; rep(i, 0, 16) if((diff >> i) & 1) u = par[u][i]; if(u == v) return u; rrep(i, 16, 0){ if(par[u][i] != par[v][i]){ u = par[u][i]; v = par[v][i]; } } return par[u][0]; } ll getDist(int u, int v){ int lca = LCA(u, v); return dist[u] + dist[v] - 2 * dist[lca]; } void solve(){ cin >> N; rep(i, 0, N-1){ int u, v, w; cin >> u >> v >> w; links[u].push_back({v, w}); links[v].push_back({u, w}); } dfs(1, -1); rep(j, 1, 16) rep(i, 1, N+1) par[i][j] = par[par[i][j-1]][j-1]; cin >> Q; while(Q--){ int u, v; cin >> u >> v; cout << getDist(u, v) << '\n'; } } πŸ”’ κ΅¬ν˜„ μ½”λ“œ 잠금

BOJ 16367 TV Show Game

·510 words·3 mins
πŸ“ 문제 정보 # 링크: https://www.acmicpc.net/problem/16367 λ²ˆμ—­ 문제 λ²ˆμ—­ # Mr. DajudaλŠ” TV μ‡Ό ν”„λ‘œκ·Έλž¨μœΌλ‘œ 유λͺ…ν•œ μ‚¬λžŒμœΌλ‘œ, 가끔 μ‹œμ²­μžλ“€μ—κ²Œ ν₯미둜운 κ²Œμž„μ„ μ œμ•ˆν•˜κ³  μƒν’ˆμ„ μƒμœΌλ‘œ μ œκ³΅ν•©λ‹ˆλ‹€. 이번 주에 κ·Έκ°€ μ œμ•ˆν•œ κ²Œμž„μ€ λ‹€μŒκ³Ό 같이 μ„€λͺ…ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ¬΄λŒ€ μœ„μ˜ k개(k > 3)의 λž¨ν”„λŠ” κ²Œμž„ μ‹œμž‘ μ‹œ λͺ¨λ‘ κΊΌμ Έ μžˆμŠ΅λ‹ˆλ‹€. νŽΈμ˜μƒ λž¨ν”„λŠ” 1λΆ€ν„° kκΉŒμ§€ λ²ˆν˜Έκ°€ 맀겨져 μžˆμŠ΅λ‹ˆλ‹€. 각 λž¨ν”„λŠ” 빨간색 λ˜λŠ” νŒŒλž€μƒ‰μ˜ 색상을 κ°€μ§€κ³  μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λž¨ν”„μ˜ 색상은 μΌœμ§€κΈ° μ „κΉŒμ§€λŠ” μ•Œ 수 μ—†μŠ΅λ‹ˆλ‹€. κ²Œμž„ μ°Έκ°€μžλ“€μ€ λ¬΄μž‘μœ„λ‘œ μ„Έ 개의 λž¨ν”„λ₯Ό μ„ νƒν•˜κ³  κ·Έ 색상을 μ˜ˆμΈ‘ν•˜λ„λ‘ μš”μ²­λ°›μŠ΅λ‹ˆλ‹€. 그런 λ‹€μŒ 각 μ°Έκ°€μžλŠ” μ„ νƒν•œ λž¨ν”„μ˜ 예츑된 색상이 기둝된 쒅이λ₯Ό κ²Œμž„ μ§„ν–‰μžμΈ Mr. Dajudaμ—κ²Œ μ œμΆœν•©λ‹ˆλ‹€. λͺ¨λ“  λž¨ν”„κ°€ μΌœμ§€λ©΄ 각 μ°Έκ°€μžλŠ” μžμ‹ μ΄ μ˜ˆμΈ‘ν•œ 색상 쀑 λͺ‡ κ°œκ°€ λž¨ν”„μ˜ μ‹€μ œ 색상과 μΌμΉ˜ν•˜λŠ”μ§€ ν™•μΈν•©λ‹ˆλ‹€. 두 개 μ΄μƒμ˜ 색상이 μΌμΉ˜ν•˜λ©΄ μƒν’ˆμ„ λ°›κ²Œ λ©λ‹ˆλ‹€.

BOJ 14908 ꡬ두 μˆ˜μ„ κ³΅

·207 words·1 min
πŸ“ 문제 정보 # 링크: https://www.acmicpc.net/problem/14908 🧐 κ΄€μ°° 및 μ ‘κ·Ό # μ§κ΄€μ μœΌλ‘œ μƒκ°ν•΄λ³΄μž μ–΄λ–€ μž‘μ—…μ˜ λ³΄μƒκΈˆ $S_i$κ°€ 크닀면, λΉ λ₯΄κ²Œ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ”κ²Œ μ’‹λ‹€. μ–΄λ–€ μž‘μ—…μ„ μ™„λ£Œν•˜λŠ”λ° κ±Έλ¦¬λŠ” μ‹œκ°„ $T_i$κ°€ μž‘λ‹€λ©΄, λΉ λ₯΄κ²Œ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ”κ²Œ μ’‹λ‹€. 이 두가지λ₯Ό μ–΄λ–»κ²Œ λ™μ‹œμ— ν™œμš©ν•  수 μžˆμ„κΉŒ? μ–΄λ–€ μ •λ‹΅ $Opt$κ°€ μ‘΄μž¬ν•œλ‹€κ³  κ°€μ •ν•΄λ³΄μž. μ΄λ•Œ, $Opt$의 μˆœμ„œμ€‘ κ°€μš΄λ° 두 μž‘μ—… $W_i, W_{i+1}$을 λ°”κΎΌλ‹€κ³  ν•΄λ³΄μž. 이 λ•Œ, 바뀐 μˆœμ„œ $Opt'$κ°€ $Opt$보닀 λ‚˜μ„ 수 μžˆμ„κΉŒ? 두 μž‘μ—…μ„ λ°”κΎΈλ©΄, $Opt' = Opt + S_i * T_{i+1} - S_{i+1} * T_i$κ°€ λœλ‹€. λ‹€μ‹œλ§ν•΄, $S_i * T_{i+1} - S_{i+1} * T_i$ 이 음수라면 더 λ‚˜μ€ 해법을 찾을 수 μžˆλ‹€. λ”°λΌμ„œ $S_i * T_{i+1} - S_{i+1} * T_i > 0$인 λ°©ν–₯, 즉 $\frac{S_i}{T_i} \geq \frac{S_{i+1}}{T_{i+1}}$ 의 μˆœμ„œλ‘œ μ •λ ¬ν•˜λ©΄ μ΅œμ ν•΄κ°€ λœλ‹€. πŸ’» 풀이 # μ½”λ“œ (C++): void solve(){ int N; cin >> N; vector<array<int, 3>> ans; // S, T, idx; rep(i, 0, N){ int S, T; cin >> S >> T; ans.push_back({T, S, i+1}); } sort(all(ans), [](const array<int, 3> &a, const array<int, 3> &b){ if(a[0]*b[1] == a[1]*b[0]) return a[2] < b[2]; return a[0]*b[1] > a[1]*b[0]; }); for(auto &p: ans) cout << p[2] << ' '; } πŸ”’ κ΅¬ν˜„ μ½”λ“œ 잠금