LintCode 1395: The Barycentre Of The Trees (树的重心-树上的DP题)

树的重心求解算法
本文介绍了一种求解多分支树重心的经典算法。通过将无根树转换为有根树,利用深度优先搜索(DFS)策略计算每个节点作为根时的子树节点数,找出使得最大子树节点数最小的节点作为树的重心。提供了详细的C++代码实现,适用于寻找具有最少最大子树节点数的树的重心。
  1. The Barycentre Of The Trees

For a multi-branch tree, if there is a node R with R as the root, and the largest sub-tree of all its sub-trees has the least number of nodes, the node R is said to be the center of gravity of the tree.
Now give you a multi-branch tree with n nodes. Find the center of gravity of this tree. If there are multiple centers of gravity, return the one with the lowest number.
x[i], y[i] represents the two points of the i-th edge.

Example
Example 1:

Given x = [1], y = [2], return 1.
Input:
[1]
[2]
Output:
1

Explanation:
Both 1 and 2 can be center of gravity, but the number of 1 is the smallest.
Example 2:

Given x = [1,2,2], y = [2,3,4], return 2.
Input:
[1,2,2]
[2,3,4]
Output:
2

Explanation:
2 is the center of gravity.
Notice
2 <= n <= 10^5
1 <= x[i], y[i] <= n

解法1:
这题是典型的树上的DP题。
思路:

  1. 先把无根树转有根树,建立tree数组,即A-B链接要建立A->B和B->A这两个链接。
  2. dfs()里面要注意对节点x遍历其子节点时,需要考虑子节点不能为x的父节点f,不然陷入死循环。
  3. 因为2)里面我们没有考虑x的父节点f,但实际上因为这是无联通图,x和f是双向链接,所以f也是x的子节点。所以还要考虑以f为节点的子节点数目,其为n - dp[x]。
class Solution {
public:
    /**
     * @param x: The vertexes of the edges
     * @param y: The vertexes of the edges
     * @return: Return the index of barycentre
     */
    int getBarycentre(vector<int> &x, vector<int> &y) {
        if (x.size() == 0) return 0;
        n = x.size() + 1;
        tree.resize(n + 1, vector<int>());  //same as tree.resize(n + 1)
        dp.resize(n + 1); //dp[i] is the the sum of the children nodes under the tree with root i plus 1, dp[i] = sum(dp[j]) + 1;
        
        for (int i = 0; i < x.size(); ++i) {
            tree[x[i]].push_back(y[i]);
            tree[y[i]].push_back(x[i]);
        }
        dfs(1, 0); //choose 1 as the root
        return gChosenNode;
    }
    
private:
    vector<vector<int>> tree;
    vector<int> dp;
    int gMaxSubTreeSize = INT_MAX;
    int gChosenNode = 0;
    int n;
    void dfs(int node, int father) {
        int maxSubTreeSize = 0;
        if (tree[node].size() == 0) {
            dp[node] = 1; //leave node
        } else {
            for (int i = 0; i < tree[node].size(); ++i) {
                int childNode = tree[node][i];
                if ( childNode != father) { // prevent endless loop
                    dfs(childNode, node);
                    dp[node] += dp[childNode];
                    maxSubTreeSize = max(maxSubTreeSize, dp[childNode]);
                }
            }
            dp[node] += 1; // add itself
        }
        maxSubTreeSize = max(maxSubTreeSize, n - dp[node]);
        if (maxSubTreeSize < gMaxSubTreeSize || (maxSubTreeSize == gMaxSubTreeSize && node < gChosenNode)) {
            gMaxSubTreeSize = maxSubTreeSize;
            gChosenNode = node;
        }
    }
};
Surface force and vorticity We first define a function which computes ∇u⋅n∇u⋅n while taking the boundary conditions on the embedded surface into account. static inline coord embed_gradient (Point point, vector u, coord p, coord n) { coord dudn; foreach_dimension() { bool dirichlet = false; double vb = u.x.boundary[embed] (point, point, u.x, &dirichlet); if (dirichlet) { double val; dudn.x = dirichlet_gradient (point, u.x, cs, n, p, vb, &val); } else // Neumann dudn.x = vb; if (dudn.x == nodata) dudn.x = 0.; } return dudn; } The force exerted by the fluid on the solid can be written FΓ=−∫∂Γ(−pI+2μD)⋅nd∂ΓFΓ​=−∫∂Γ​(−pI+2μD)⋅nd∂Γ with ΓΓ the solid boundary. It can be further decomposed into a pressure (i.e. “form”) drag Fp=∫∂Γpnd∂ΓFp​=∫∂Γ​pnd∂Γ and a viscous drag Fμ=−∫∂Γ2μD⋅nd∂ΓFμ​=−∫∂Γ​2μD⋅nd∂Γ These two vectors are computed by the embed_force() function. trace void embed_force (scalar p, vector u, face vector mu, coord * Fp, coord * Fmu) { coord Fps = {0}, Fmus = {0}; foreach (reduction(+:Fps) reduction(+:Fmus), nowarning) if (cs[] > 0. && cs[] < 1.) { To compute the pressure force, we first get the coordinates of the barycentre of the embedded fragment, its area and normal, and then interpolate the pressure field on the surface. coord n, b; double area = embed_geometry (point, &b, &n); area *= pow (Delta, dimension - 1); double Fn = area*embed_interpolate (point, p, b); foreach_dimension() Fps.x += Fn*n.x; To compute the viscous force, we first need to retrieve the local value of the viscosity (ideally at the barycentre of the embedded fragment). This is not completely trivial since it is defined on the faces of the cell. We use a surface-fraction-weighted average value. if (constant(mu.x) != 0.) { double mua = 0., fa = 0.; foreach_dimension() { mua += mu.x[] + mu.x[1]; fa += fm.x[] + fm.x[1]; } mua /= fa; To compute the viscous force, we need to take into account the (Dirichlet) boundary conditions for the velocity on the surface. We only know how to do this when computing the normal gradient ∇u⋅n∇u⋅n using the embed_gradient() function. We thus need to re-express the viscous force using only normal derivatives of the velocity field. If we assume that uu is constant on the boundary, then ∇u⋅t=0∇u⋅t=0 with tt the unit tangent vector to the boundary. We thus have the relations ∇u=(∇u⋅n)n+(∇u⋅t)t=(∇u⋅n)n∇u=(∇u⋅n)n+(∇u⋅t)t=(∇u⋅n)n D=12(∇u+∇Tu)=12(2(∇u⋅n)nx(∇u⋅n)ny+(∇v⋅n)nx(∇u⋅n)ny+(∇v⋅n)nx2(∇v⋅n)ny)D=21​(∇u+∇Tu)=21​(2(∇u⋅n)nx​(∇u⋅n)ny​+(∇v⋅n)nx​​(∇u⋅n)ny​+(∇v⋅n)nx​2(∇v⋅n)ny​​) Fμ=−∫Γ([2μ(∇u⋅n)nx]nx+μ[(∇u⋅n)ny+(∇v⋅n)nx]ny[2μ(∇v⋅n)ny]ny+μ[(∇u⋅n)ny+(∇v⋅n)nx]nx)Fμ​=−∫Γ​([2μ(∇u⋅n)nx​]nx​+μ[(∇u⋅n)ny​+(∇v⋅n)nx​]ny​[2μ(∇v⋅n)ny​]ny​+μ[(∇u⋅n)ny​+(∇v⋅n)nx​]nx​​) Fμ=−∫Γ(μ[(∇u⋅n)(nx2+1)+(∇v⋅n)nxny]μ[(∇v⋅n)(ny2+1)+(∇u⋅n)nxny])Fμ​=−∫Γ​(μ[(∇u⋅n)(nx2​+1)+(∇v⋅n)nx​ny​]μ[(∇v⋅n)(ny2​+1)+(∇u⋅n)nx​ny​]​) assert (dimension == 2); coord dudn = embed_gradient (point, u, b, n); foreach_dimension() Fmus.x -= area*mua*(dudn.x*(sq(n.x) + 1.) + dudn.y*n.x*n.y); } } *Fp = Fps; *Fmu = Fmus; } In two dimensions, embed_vorticity() returns the vorticity of velocity field u, on the surface of the embedded boundary contained in the cell. p is the relative position of the barycentre of the embedded fragment and n its normal. #if dimension == 2 double embed_vorticity (Point point, vector u, coord p, coord n) { We compute ∇u⋅n∇u⋅n, taking the boundary conditions into account. coord dudn = embed_gradient (point, u, p, n); The vorticity is then obtained using the relations ω=∂xv−∂yu=(∇v⋅n)nx−(∇u⋅n)nyω=∂x​v−∂y​u=(∇v⋅n)nx​−(∇u⋅n)ny​ return dudn.y*n.x - dudn.x*n.y; } #endif // dimension == 2 将以上官网的代码中穿插的解释翻印并总结,并总结其中的所有代码
06-05
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值