poj 2057 The Lost House 贪心思想在动态规划上的应用

  浅谈贪心思想在动态规划中的应用 ----- 黄劲松   论文中的例题,其中也附有详接

 

  讲讲自己的理解吧. 

  

  题目所求为, 使用某种特定策略,使从根节点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 )

 

解题代码

  

View Code
// 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;
}

 

posted @ 2013-01-16 22:16  yefeng1627  阅读(501)  评论(0编辑  收藏  举报

Launch CodeCogs Equation Editor