[백준/BOJ] 백준 2197번 : 분해 반응
2022. 8. 18. 03:02ㆍ알고리즘 문제풀이
https://www.acmicpc.net/problem/2197
2197번: 분해 반응
첫째 줄에 두 정수 N, M(1 ≤ M ≤ N)이 주어진다. 다음 N-1개의 줄에는 원자들의 연결 상태를 나타내는 서로 다른 두 정수 A, B(1 ≤ A, B ≤ N)가 주어진다. 이는 A번 원자와 B번 원자가 결합을 이루고
www.acmicpc.net
루트가 1번 노드인 트리를 만들고, 리프 노드부터 위로 올라가면서 cache[노드][크기]에 해당 노드가 루트인 서브 트리에서 해당 크기로 만드는데 최소로 자르는 횟수를 채운 뒤, 모든 노드를 확인하며 각 노드에서 크기 m을 만드는데 자르는 최소 횟수 중 가장 작은 값을 찾는 방법으로 문제를 해결했다. 각 노드의 cache를 채울 때 해당 노드의 자식 노드를 이용했는데, 자식 노드에서 이미 만들어진 cache와 자신이 가지고 있는 cache를 조합해서 자신의 cache를 업데이트해 나아갔다. 이때 주의해야 될 점은 어떤 자식 노드로 자신의 cache를 업데이트해 나아가는 중에 현재 업데이트하고 있는 해당 노드의 cache정보를 현재 업데이트에 사용하지 않도록 주의해야 한다. 이를 방지하기 위해 현재 노드의 큰 크기의 cache 정보부터 업데이트해 나아갔다. (큰 크기의 cache는 작은 크기의 cache정보를 업데이트하는 데 사용되지 않기 때문)
코드
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
int n, m;
vector<int> adj[155];
vector<int> visited(155, 0);
vector<int> children[155];
vector<int> parent(155, 0);
vector<int> tree_size(155, 0); //해당 정점이 루트인 서브트리의 크기
vector<vector<int>> cache(155, vector<int>(155, 987654321)); //[정점][크기] = 해당정점이 루트인 서브트리에서 해당 크기로 만드는데 최소 자르는 횟수
vector<int> order;
void MakeTree(int here) {
visited[here] = 1;
tree_size[here]++;
for (int i = 0; i < adj[here].size(); i++) {
int there = adj[here][i];
if (visited[there])
continue;
MakeTree(there);
children[here].push_back(there);
parent[there] = here;
tree_size[here] += tree_size[there];
}
}
void MakeOrder(int start) {
queue<int> q;
q.push(start);
while (!q.empty()) {
int here = q.front();
q.pop();
order.push_back(here);
for (int i = 0; i < children[here].size(); i++) {
int there = children[here][i];
q.push(there);
}
}
}
int main()
{
cin.tie(NULL);
ios_base::sync_with_stdio(false);
cin >> n >> m;
for (int i = 0; i < n - 1; i++) {
int a, b;
cin >> a >> b;
adj[a].push_back(b);
adj[b].push_back(a);
}
MakeTree(1);
MakeOrder(1);
reverse(order.begin(), order.end());
//리프노드 부터 위로 가면서 확인한다
for (int a = 0; a < order.size(); a++) {
int here = order[a];
cache[here][1] = children[here].size(); //자신 노드 모두 끊기
cache[here][tree_size[here]] = 0; //아무것도 끊지 않는 경우
//리프노드일때
if (children[here].size() == 0)
continue;
//here노드의 cache 채우기
//각 자식노드를 이용
for (int i = 0; i < children[here].size(); i++) {
int there = children[here][i]; //here의 자식 노드
for (int j = tree_size[here]; j >= 1; j--) { //지금 업데이트하는것을 지금 업데이트하는곳에 사용하지 않기위해 큰것부터 채우기
//cache[here][j]만들기
for (int k = 1; k < j; k++) { //이전에서 k개 고르고, there에서 j-k개 고르는 경우
if (cache[here][k] == 987654321) //이전에 k가 계산된적이 없을때
continue;
if (tree_size[there] >= j - k) //there에서 j-k개를 고를 수 있을때
cache[here][j] = min(cache[here][j], cache[here][k] + cache[there][j - k] - 1);
}
}
}
}
int result = 987654321;
for (int i = 1; i <= n; i++) {
//루트 노드일때
if (i == 1)
result = min(result, cache[i][m]);
//루트 노드가 아닐때 (부모로 가는 간선도 하나 잘라야 된다)
else
result = min(result, cache[i][m] + 1);
}
cout << result;
return 0;
}
'알고리즘 문제풀이' 카테고리의 다른 글
[백준/BOJ] 백준 15554번 : 전시회 (0) | 2022.08.18 |
---|---|
[백준/BOJ] 백준 21279번 : 광부 호석 (0) | 2022.08.18 |
[백준/BOJ] 백준 5021번 : 왕위 계승 (0) | 2022.08.18 |
[백준/BOJ] 백준 22959번 : 신촌 수열과 쿼리 (0) | 2022.08.17 |
[백준/BOJ] 백준 2110번 : 공유기 설치 (0) | 2022.08.17 |