Greedy on Tree
트리는 아주 특수한 그래프의 일종이고, 상당히 강력한 성질들이 많이 존재한다. 또한 subtree 내부와 외부가 상호작용하는 정도가 작다는 성질 때문에 다양한 object의 최적해들을 greedily 구할 수 있는 경우가 많이 존재한다. 이 글에서는 기록을 목적으로 몇 가지 문제들에 대한 내 증명을 적어둔다.
Diameter of Tree
트리의 지름을 구하는 문제는, 가장 떨어진 거리가 먼 두 정점 쌍을 찾는 문제이다. 임의의 정점 \(i\)에서 가장 멀리 떨어진 정점을 \(a\)라고 하자. \(a\)에서 가장 멀리 떨어진 정점을 \(b\)라고 하면, \((a, b)\)가 지름을 이루는 두 정점이라는 것이 claim이다. 트리의 아무 지름 \((c, d)\)를 잡고, \(c\)에서 \(d\)로 가는 경로 위에 놓인 정점들이 순서대로 \(u_1, \ldots, u_k\)라고 하자. 그러면 전체 트리는 \(c\)에서 \(d\)로 가는 정점들과, \(u_i\)를 루트로 하는 subtree들로 구성된 꼴이 된다. \(c\)와 \(d\)는 항상 차수가 \(1\)인 정점인 것도 확인할 수 있다. 또한 이런 경우, \(u_t\)의 subtree는 \(u_t\)의 깊이를 \(0\)으로 볼 때 기껏해야 \(min(t, k+1-t)\)의 깊이를 가지게 된다. 그게 아니라면 \(u_t\) 내부에서 가장 깊은 깊이의 정점을 잡으면, \(c\)나 \(d\)와 연결했을 때 둘 중 하나가 \((c, d)\)의 거리보다 길다.
그러므로 위에서 설명한 greedy 과정에서 \(i\)가 \(u_t\)의 subtree에 있는 정점이라고 하자. WLOG \(t < \frac{k+1}{2}\)라고 하면, \(a\)에 해당하는 점은 \(d\)가 되거나, \(d(i, a) = d(i, d)\)를 최소한 만족한다. 그런데 \(a \neq d\)인 경우 어찌 됐건 \((c, a)\)도 지름을 이루는 정점일 수밖에 없다. 그러면 항상 greedy 과정에서 잡히는 \(a\)는 반드시 어떠한 지름을 구성하는 정점 쌍에 포함될 수 있는 정점이라는 뜻이므로, 항상 \(b\)가 \((a, b)\)가 되도록 잡히게 된다.
주유소 (KOI 2023)
트리가 주어질 때 정점들의 부분집합 \(S\)를 잡아서, 임의의 길이 \(k\)인 simple path 중 최소 하나의 정점이 \(S\)에 포함되게 하는 최소의 \(\vert S \vert\)를 구하는 문제이다. 먼저 이 문제를 dp로 접근하자. \(dp[i]\)는 \(i\)번 subtree만을 고려했을 때, 조건을 만족하는 주유소 개수의 최솟값이라 하자. \(i\)의 자식을 \(c_1, \ldots, c_t\)라 하자. 모든 길이 \(k\)인 경로는 어떤 \(c_j\)의 subtree 안에 완전히 속하거나, \(i\)를 포함하는 경로 두 가지 종류뿐이다. 그러므로 \(c_j\) subtree 내에는 최소 \(dp[c_j]\)만큼의 주유소가 있어야 한다. 또한 각 자식의 subtree에서의 최적해를 union한 주유소 집합에, \(i\) 정점에까지 주유소를 설치하면 이는 조건을 만족하는 주유소 집합이다. 따라서 다음이 성립한다. $$ \sum_{j=1}^t dp[c_j] \leq dp[i] \leq \sum_{j=1}^t dp[c_j] + 1$$
그러므로 \(i\)에 주유소를 반드시 설치해야만 하는지 여부를 구분해줄 수 있으면 dp 값들을 전부 계산할 수 있다. 이제 \(i\)로부터 각 subtree들로 path를 '침투'시킨다고 할 때, 주유소들을 피해 침투할 수 있는 최대 깊이를 생각하자. 좀 더 엄밀하게는, 자기 자신을 포함하여 ancestor들 중 주유소가 모두 설치되어있지 않은 정점의 최소 깊이가 침투 깊이이다. 이 때 \(t \geq 2\)이면 침투된 깊이가 가장 큰 것 두 개의 합이 \(k\) 이상일 경우 \(i\)가 반드시 주유소여야 한다. (정확히 말하자면 \(i\)가 아니라 subtree 안쪽에 주유소를 하나 더 설치하는 것도 방법이지만, 어쨌든 주유소가 자식들 내부에서의 배치만으로는 부족하다는 관점에서) \(t = 1\)이면 유일한 침투된 깊이가 \(k\) 이상인지 여부가 중요하다. 즉 각 subtree에서 계산했어야 하는 정보를 하나 더 발견했다. 이제 dp 정의를 다음과 같이 바꾼다: \(dp[i]\)는 \(i\)번 subtree만을 고려했을 때, 조건을 만족하는 주유소 배치 \(S\)들 중 (\(\vert S \vert\), 침투 깊이) tuple의 사전순 최솟값이다.
dp 정의가 바뀌었으니, dp 전이도 다시 생각해봐야 한다. 자식 subtree 중 최적 개수보다 더 많은 주유소를 사용하느니, 자식들에선 최적 개수로 주유소를 두고 \(i\)에 주유소를 하나 더 설치하는 게 tuple의 두 번째 값에서 이득을 본다. 또 주유소를 추가로 설치하지 않는 걸 판별하기 위해서는 앞서 설명한 논리에 따라 자식 subtree 내의 주유소 배치가 전부 \(dp[c_j]\)가 지정하는 사전순 최소 tuple인 상태가 되도록 설치하여야 한다. 그러면 \(dp[i]\) tuple의 첫 번째 값은 최적인지 아닌지 알 수 있고, 두 번째 값까지 최소화하는 방법을 생각해야 한다. 그런데 이것도 따지고 보면 간단하다. \(i\)에서 주유소 추가 설치가 필요한 케이스인 경우 당연히 \(i\)에 직접 설치하는 게 침투 깊이를 \(0\)으로 만들게 되므로 최소이고, 주유소 추가 설치가 필요하지 않다면 \(i\)에서부터의 침투 깊이는 자식 subtree들 중 최대 침투 깊이에 \(+1\)을 한 값이기 때문에 자식 subtree에서 사전순 최소 tuple을 사용하는 것이 이득이기 때문이다.
그러므로 dp 전이 과정에서 무조건 자식 dp값을 사용하는 것이 이득이고, greedy의 관점에서 이러한 greedy 전략이 정당함을 증명할 수 있다.
Logistical Warehouse 2 (2021 ICPC Seoul Regional)
트리와 \(k\)가 주어질 때, 반지름 \(k\)짜리 cover를 사용해서 모든 정점을 덮기 위한 최소의 개수를 묻는 문제이다. 위의 문제와 접근법이 거의 동일하지만, 이 증명은 좀 technical한 편이라 마음에 들진 않는 상태이다. 예전에 증명을 찾아봤는데 안 나와서 어떻게든 만들어봤다. 여기서는 바로 dp 정의를 서술한다. \(dp[i]\)를 \(i\)번 subtree만을 고려했을 때, \(i\)를 깊이 \(0\)으로 보았을 때 깊이가 \(k\) 이하인 모든 정점을 덮는 cover 배치 \(S\)들 중 (\(\vert S \vert\), \(S\)에 의해 아직 덮이지 않은 정점의 최대 깊이) tuple의 사전순 최소라고 정의하자. 이러한 정의의 motivation은, \(i\) 정점으로부터 \(k\)만큼 아래에 있는 정점이 아직 덮이지 않은 경우, 그것을 덮을 수 있는 유일한 cover 위치가 \(i\)가 되게 하기 위한 방안이다.
위의 문제와 정확히 같은 방식으로, \(i\)를 구성하는 cover의 개수는 각 subtree 내의 cover의 최적 개수 합과 같거나 최대 \(1\) 더 크다. (\(i\)를 중심으로 하는 cover를 두면 조건을 만족하므로) 이 때 \(i\)에 cover를 두어야 하는지 여부는, subtree들 중 덮이지 않은 정점의 최대 깊이들 중 어떻게 해도 \(k-1\) 위치인 것이 있을 때 cover를 필요로 한다. 반대로 그렇지 않으면 cover가 필요하지 않으며, 이 경우 \(dp[i]\)에서 덮이지 않은 정점의 최대 깊이는 자식 subtree에서 덮이지 않은 정점들의 최대 깊이들의 최댓값에 \(+1\)한 값이다. 그러므로 역시 dp 전이가 greedy적으로 작동한다.
Fire Extinguishers (POI 2008/2009 Stage 1)
공식 에디토리얼도 존재하는 문제지만, 아직 증명을 이해하지 못 했다. 위와 같은 방식으로 증명이 가능할 거라고 생각하는데, 아직 모름.