浅谈贪心思想在动态规划中的应用 ----- 黄劲松 论文中的例题,其中也附有详接
讲讲自己的理解吧.
题目所求为, 使用某种特定策略,使从根节点rt ,依次到每个叶子节点最少步长. 再除以叶子节点数量. 即为最终期望值.
对于一个以 rt 为根的子树上, 我们将其分为 House在子树rt上的步长总数Fa , 以及不在子树上步长总数Fb:
表示 House 在 该rt为根子树上的 步长总数
表示 House 不在 该rt为根子树上的 步长总数
表示 该子树上 叶子节点数量
则所求期望为:
若节点 u, 有 k 个子节点, 按照 s1, s2 , ... , sk 的固定顺序访问, 则 计算过程为:
Fa(u) = 0; Fb(u) = 0;
for( i = 1 ... k )
Fa(u) += ( Fb(u)+1 ) * Leave( Si ) + Fa( Si ) // 若House在Si子树时, 前面 1..i-1 个已经走过,且数量是叠加, 此时走向 SI 子树时, +1 步长,其有 Leave( Si ) 个叶子节点,方案数要叠加
Fb(u) += Fb( Si ) + 2 // 若House不在 Si 子树,则返回 的步长花费
使用数学公式表示为:
现在的问题就是如何决定访问儿子的顺序,不同的访问顺序会产生不同的Fa[u]。我们要使得Fa[u]尽量的小。
将公式进行处理可以得到如下:
可以看到 若将 子节点 位置改变, 则对于公式 后两项没有影响,
所以对于 子节点 间位置关系, 我们仅需考虑第一项就可以了
令
为 两子节点
顺序放置时 值。
为 两子节点
交换放置时 值。
则 两值做差 得到:
所以我们得出结论, 顺序位置 则只跟元素
的信息有关,于别的元素的排列情况无关,所以元素
是可比的。
所以我们可以根据此得出 任意 根节点u的子节点 (i,j) 两两间关系,
又 对于 根节点 u 的任意三个子节点 a, b, c ,存在如下关系时: ( a < b, b < c )
两式相乘后,得
说明其满足 闭包传递性 , 则我们可以通过 先序关系 得出 全序关系, 即可得出 Fa( u )
解题代码

// code by: yefeng1627 // time: 2013-1-16 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<iostream> #include<algorithm> #include<vector> using namespace std; const int N = 1010; struct node { int fa,fb,L; bool flag; }T[N]; vector<int> Q[N]; int n; bool cmp( int x, int y ) {return ( (T[x].fb+2)*T[y].L < (T[y].fb+2)*T[x].L );} void dfs( int u ) {// return the fa(u) // 首先得到 u 的所有子节点信息 for(int i = 0; i < (int)Q[u].size(); i++) dfs( Q[u][i] ); // 初始化 T[u].fa = T[u].fb = T[u].L = 0; // 叶子节点 if( Q[u].size() == 0 ) T[u].L = 1; if( Q[u].size() > 0 ){ sort( Q[u].begin(), Q[u].end(), cmp ); for(int i = 0; i < Q[u].size(); i++) { int v = Q[u][i]; T[u].fa += ( T[u].fb+1 )*T[v].L + T[v].fa; T[u].fb += T[v].fb+2; T[u].L += T[v].L; } // 若节点u 上存在毛毛虫,则返回花费0 if( T[u].flag ) T[u].fb = 0; } } int main() { while( scanf("%d", &n) , n ) { for(int i = 0; i <= n; i++) Q[i].clear(); char str[2]; for(int x = 1; x <= n; x++) { int pre; scanf("%d %s", &pre, str); if( pre != -1 ) Q[pre].push_back(x); T[x].flag = ( (str[0]=='Y') ? true : false ); } dfs(1); double ans = 1.0*T[1].fa/T[1].L; printf("%.4f\n", ans); // printf("Fa(rt) = %d\n", T[1].fa ); } return 0; }