如何得到一棵树的最小顶点覆盖的好算法?
输入:
节点的邻居。
输出:
最小顶点数。
如何得到一棵树的最小顶点覆盖的好算法?
节点的邻居。
最小顶点数。
阅读了这里的答案后,我并没有完全理解,所以我想从这里发布一个帖子。
总体思路是将树以任意节点为根,然后询问该根节点是否在覆盖集中。如果是,则通过递归计算其子树的最小顶点覆盖。如果不是,则必须在根节点的每个子节点上放置顶点,以覆盖根节点和其子节点之间的每条边。在这种情况下,需要对根节点的孙子进行递归。
例如,如果您有以下树:
A
/ \
B C
/ \ / \
D E F G
注意,通过检查,您知道最小顶点覆盖是{B, C}
。我们将找到这个最小覆盖。
我们从A
开始。
A
在覆盖范围内我们移至B
和C
的两个子树,并对此算法进行递归。我们不能简单地说B
和C
不在覆盖范围内,因为即使AB
和AC
已被覆盖,我们也无法确定是否需要将B
和C
包含在覆盖范围内。
(考虑以下树,其中根和其中一个子节点都在最小覆盖范围内({A, D}
)
A
/|\___
B C D
/|\
E F G
但我们知道AB
和AC
必须被覆盖,所以我们必须将B
和C
添加到覆盖集合中。由于B
和C
已经在覆盖集合中,所以我们可以递归它们的子节点,而不是递归B
和C
(即使我们这样做,它也不会给我们更多信息)。
令C(x)
为以x
为根的最小覆盖集合的大小。
那么,
C(x) = min (
1 + sum ( C(i) for i in x's children ), // root in cover
len(x's children) + sum( C(i) for i in x's grandchildren) // root not in cover
)
我希望你能在这里你可以找到更多相关的问题答案。
我考虑了我的解决方案,可能需要修改,但只要动态规划是其中一个标签,您可能需要:
阅读完这篇文章后。将上述算法更改为查找最大独立集,因为在维基百科文章中说明:
一个集合是独立的,当且仅当它的补集是顶点覆盖。
因此,通过将min更改为max,我们可以找到最大独立集,并通过补集找到最小的顶点覆盖,由于这两个问题是等价的。
{- Haskell implementation of Artem's algorithm -}
data Tree = Branch [Tree]
deriving Show
{- first int is the min cover; second int is the min cover that includes the root -}
minVC :: Tree -> (Int, Int)
minVC (Branch subtrees) = let
costs = map minVC subtrees
minWithRoot = 1 + sum (map fst costs) in
(min minWithRoot (sum (map snd costs)), minWithRoot)
#include <bits/stdc++.h>
using namespace std;
vector<vector<int> > g;
int dp1[100010], dp2[100010];
void dfs(int curr, int p){
for(auto it : g[curr]){
if(it == p){
continue;
}
dfs(it, curr);
dp1[curr] += min(dp1[it], dp2[it]);
dp2[curr] += dp1[it];
}
dp1[curr] += 1;
}
int main(){
int n;
cin >> n;
g.resize(n+1);
for(int i=0 ; i<n-1 ; i++){
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0);
cout << min(dp1[1], dp2[1]);
return 0;
}
DFS(node x)
{
discovered[x] = true;
/* Scan the Adjacency list for the node x*/
while((y = getNextAdj() != NULL)
{
if(discovered[y] == false)
{
DFS(y);
/* y is the child of node x*/
/* If child is not selected as a vertex for minimum selected cover
then select the parent */
if(y->isSelected == false)
{
x->isSelected = true;
}
}
}
}
我会简单地使用线性规划来解决最小顶点覆盖问题。 将其表述为整数线性规划的公式可以看起来像这个:ILP formulation
我认为你自己的实现不会比这些高度优化的LP求解器更快。