Tree에서 K 가장자리에 액세스하기위한 최소 정점 커버
-
28-09-2020 - |
문제
$ n-1 $ << "> $ N-1 $ <"수학 용기 "> $ N $ vertices에서 최소 숫자를 찾아야합니다./ span> 가장자리가 $ k $ 이이 트리의 가장자리 가이 정점에 연결됩니다.
예를 들어 $ n= 9 $ 및 $ k= 6 $ 이면 우리는 이것을 가지고 있습니다.나무 : Edges | Vertice #1 | Vertice #2
1 1 2
2 1 3
3 1 4
4 2 5
5 2 6
6 3 7
7 4 8
8 4 9
.
$ \ mathrm {min}= 2 $
여야합니다.어떤 생각?
해결책
$ \ mathcal {o} (nk) $ DP 접근 방식이 있습니다.
옆에있는 정점을 선택하면 가장자리를 덮습니다. 임의의 정점 $ r $ 의 나무를 뿌리줍니다. $ dp [i] [b] [t] $ 을 노드 $ i 하위 트리에서 대부분의 $ T $ 노드에서 선택하여 덮일 수있는 $ . $ b= 0 $ 노드 $ i $ 을 선택할 수 없습니다.="수학 용기"> $ b= 1 $ 우리는 그것을 선택해야합니다.
이 DP를 계산하면 $ k $ 가장자리가 가장 작은 $ max (DP [r] [0], DP [r] [1] [T]) \ GEQ의 $ T $ span> k $ span>. 또한 $ dp 클래스="수학 컨테이너"> $ t \ leq k $ 에만 $ dp $ 을 계산하는 것이 충분합니다. $ k
DP를 계산하기 위해 재발을 부여하기 위해 우리는 먼저 배낭 - 기능을 제공합니다. $ K (v_ {1}, \ dots, v_ {m}) $
와 같은 배열이 되십시오.\ begin {방정식 *} K (v_ {1}, \ dots, v_ {m}) [T]=max_ {T_ {1} + \ dots + t_ {m}= t} \ sum_ {j= 1} ^ {m} v_ { J} [T_ {J}] \ end {방정식 *}
$ k (k (v_ {1}, \ dots, v_ {m-1}), v_ {m})= k (v_ {1}, \ 점, v_ {m}) $ 및 $ k (a, b) $ 은 $ \ mathcal {o} (| a | \ cdot | b |) $ 시간. 따라서 $ k (v_ {1}, \ dots, v_ {m}) $ 은 $ \ mathcal {o}를 찍습니다. (\ sum_ {i= 2} ^ {m} | v_ {i} | \ sum_ {j= 1} ^ {i-1} | v_ {j} |) $ 우리가 결합한 순서에 관계없이 세트가 있습니다. 우리가 첫 번째 $ k $ DP의 값만에 관심이있는 경우 복잡성은 $ \ MathCal {o} (\ sum_ {i= 2} ^ {m} | v_ {i} | \ min (k, \ sum_ {j= 1} ^ {i-1} | v_ {j} |)) $ < / span>
$ C_ {i} $ 노드 $ i $ 의 자식 세트가되도록하십시오. $ C_ {ij} $ $ j $ th $ i $ . 그때 \ begin {gatel *} DP [i] [0] [T]= K (v_ {1}, \ dots, v_ {| c_ {i} |}) [~] \\ DP [i] [1] [t]= | c_ {i} | + k (v '_ {1}, \ dots, v'_ {| c_ {i} |}) [T-1] \ end {gather *} 어디 \ begin {gatel *} v_ {j} [t]=max (dp [c_ {ij}] [0] [T], DP [C_ {ij}] [1] [T] + 1) \\ v '_ {j} [t]=max (DP [C_ {ij}] [0] [T], DP [C_ {ij}] [1] [T]) \\ \ end {gather *} 이 재귀로 답변을 계산하면 $ \ mathcal {o} (NK) $ 시간이 걸립니다. 비공식적으로 이것은 알고리즘의 과정에서 단일 요소 DPS를 전체 트리를 나타내는 DP로 결합하기 때문입니다. 우리는 대부분의 $ \ frac {n} {k} $ 수학 용기 "세트의 조합"> $ k $ 그리고 모든 요소는 대부분의 $ 2k $ 시간 ( $ x \ $ 비용이있는 경우) US $ | b | $ K (A, B) $ 을 계산할 때 $ k (A, B) $ ) $ k $ 의 세트로 $ \ mathcal {o} (k) ^ {2} \ frac {n} {k} + kn)=mathcal {o} (nk) $ . 이것은 쉽지만 유도로 공식화하기가 지루합니다.
#include <iostream>
#include <vector>
#include <tuple>
using namespace std;
const int INF = (int)1e9 + 7;
vector<int> knapsack(const vector<int> a, const vector<int> b, int k) {
int n = a.size();
int m = b.size();
vector<int> c(n+m-1, -INF);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) c[i+j] = max(c[i+j], a[i] + b[j]);
}
if (c.size() > k) c.resize(k);
return c;
}
pair<vector<int>, vector<int>> dfs(int i, int p, int k, const vector<vector<int>>& g) {
vector<int> dp0 = {0, 0};
vector<int> dp1 = {-INF, (int)g[i].size() - (p != -1)};
for (auto t : g[i]) {
if (t == p) continue;
vector<int> dp0_t, dp1_t;
tie(dp0_t, dp1_t) = dfs(t, i, k, g);
int m = dp0_t.size();
vector<int> off0(m), off1(m);
for (int j = 0; j < m; ++j) off0[j] = max(dp0_t[j], dp1_t[j] + 1);
for (int j = 0; j < m; ++j) off1[j] = max(dp0_t[j], dp1_t[j]);
dp0 = knapsack(dp0, off0, k+1);
dp1 = knapsack(dp1, off1, k+1);
}
return {dp0, dp1};
}
int minCover(int k, const vector<vector<int>>& g) {
vector<int> dp0, dp1;
tie(dp0, dp1) = dfs(0, -1, k, g);
for (int i = 0;; ++i) {
if (max(dp0[i], dp1[i]) >= k) return i;
}
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
int n, k;
cin >> n >> k;
vector<vector<int>> g(n);
for (int i = 0; i < n-1; ++i) {
int a, b;
cin >> a >> b;
--a; --b;
g[a].push_back(b);
g[b].push_back(a);
}
int t = minCover(k, g);
cout << t << '\n';
}
. 다른 팁
간단한 해결책은 $ dp (n, 2, n) $ 을 사용하는 것입니다. $ DP (i, 0, j) $ $ \ leq j를 사용하여 얻을 수있는 최대 가장자리 수가 가능합니다. 노드 $ i $ , 노드 $ i $ 자체로 루트 컨테이너에 루트 노드> 정점 덮개에 있지 않습니다. $ dp (i, 1, j) $ 이 동일하도록하자 $ i $ 이 포함됩니다 버텍스 커버에서.
전환 자체는 분명하지는 않지만, 배낭과 유사한 방법을 사용하여 수행 할 수 있습니다. 노드 $ i $ 의 모든 아이들을 고려하십시오. $ DP (CH, 0, C) $ 및 $ DP (CH, 1, C) $의 모든 값을 사용하십시오. 두 개의 개별 배낭에있는 항목으로 $ dp (i, 0) $ 및 전체 배열 $ dp (i, 1) $ . 항목 비용은 $ c $ 이고 값은 다음과 같습니다.
$ dp (i, 0) $ : $ dp (ch, 0, c) $ 은 $ dp (ch, 0, c) $ ; $ DP (CH, 1, C) $ 은 $ dp (CH, 1, C) + 1 $ < / span>.
$ dp (i, 1) $ : $ dp (ch, 0, c) $ $ dp (CH, 0, C) +1 $ ; $ DP (CH, 1, C) $ 은 $ dp (CH, 1, C) + 1 $ < / span>.
전체 배열 $ dp (i, 0) $ 및 $ dp (i, 1) $ 모든 $ kn (last, j) $ 의 값의 끝 값에서 직접 컨테이너 "> $ j $ ). 배낭에는 노드 당 $ o (\ # 하위 * n) $ 항목이 $ o (\ # 어린이)에서 실행됩니다. * n * n) 노드 당 $ . 따라서 솔루션의 총 복잡성은 $ o (n ^ 3) $ 입니다. 동일한 노드가 취해지지 않도록하는 두 항목을 방지하기 위해 전통적인 0-1 배낭을 약간 수정해야합니다. 이것은별로 어렵지 않습니다. 또한 $ DP (i, 1) $ 어레이를 계산할 때 노드 $ i $ 자체는 정점 덮개의 여분의 노드입니다.
이 하나보다 더 빨리 실행되는 솔루션이 있는지 확실하지만 나는 그것을 의심하지 않을 것입니다.