zoukankan      html  css  js  c++  java
  • poj 1947 Rebuilding Roads(树形dp)

    树形dp,顾名思义,就是在“树”的结构下用动态规划求最值。既然是在“树”形的结构下进行的,那么做这类题的第一步是先建树,然后顺着树的结构进行dp,一般从两个方向进行:

    1. 根—>叶:不过这种动态规划在实际的问题中运用的不多,也没有比较明显的例题。

    2. 叶->根:既根的子节点传递有用的信息给根,完后根得出最优解的过程。

    至于状态转移公式,这要具体题目具体分析。呃,来说说这道题。

    题意:各处含有N个节点的树,问你最少剪去几个边可以得到一颗包含P个节点的子树。

    思路:dp[i][j]表示以i为根的子树包含j个节点最少剪去的边,若j为1的话dp[i][1] 就等于i的子节点数,然后就是0-1背包的问题了。还是看代码吧;

    View Code
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <map>
    #include <math.h>
    #define  N 154
    #define  INF  0xffff
    using namespace std ;
    
    vector<int>node[N] ;
    int dp[N][N] , p[N] ;
    int n , m ;
    
    int min( int x , int y )
    {
        return x < y ? x : y ;
    }
    
    int dfs( int root )
    {
        int i , j , k ;
        //从叶子节点开始
        for ( i = 0 ; i < node[root].size() ; i++ )
        {
            dfs( node[root][i] );
        }
        dp[root][1] = node[root].size();//初始化每个节点为它子节点的数
        for ( i = 0 ; i < node[root].size() ; i++ )
        {
            for ( j = m - 1; j >= 0 ; j-- )
            if ( dp[root][j] != INF )
            for ( k = 1 ; k <= m - j ; k++ )
            if ( dp[node[root][i]][k] != INF )//进行背包运算,dp[root][j] + dp[node[root][i]][k] 是
            //求以root为根的子树包含j+k个子节点要剪去的最少边,
            //-1是减去root与node[root][i] 之间的连线
            dp[root][j+k] = min ( dp[root][j] + dp[node[root][i]][k] - 1 ,  dp[root][j+k] );
        }
        return dp[root][m] ;
    }
    
    int main()
    {
        int i , j , minx ;
    
        while ( scanf( "%d%d" , &n , &m ) != EOF )
        {
            for ( i = 0 ; i <= n ; i++ )
            for ( j = 0 ; j <= m ; j++ )
            dp[i][j] = INF ;
    
            memset( p , 0 , sizeof ( p ));
            for ( i = 1 ; i < n ; i++ )
            {
                int x , y ;
                scanf( "%d%d", &x , &y );
                node[x].push_back( y );
                p[y] = x ;
            }
    
            int root = 1 ;
            while ( p[root] != 0 )
            root = p[root] ;
    
            minx = dfs( root );
            for ( i = 1 ; i <= n ; i++ )
            if ( i != root && dp[i][m] < minx )
            minx = dp[i][m] + 1;
    
            cout<<minx<<endl;
        }
        return 0 ;
    }
  • 相关阅读:
    [R] read.table的check.names参数防止读入数据时列名前自动加上"X."
    【宏基因组】MEGAN4,MEGAN5和MEGAN6的Linux安装和使用
    洛谷—— P1077 摆花
    洛谷—— P2733 家的范围 Home on the Range
    BZOJ——T 1801: [Ahoi2009]chess 中国象棋
    洛谷—— P1379 八数码难题
    BZOJ——T 1800: [Ahoi2009]fly 飞行棋
    几种outofmemory
    几种常见web攻击手段及其防御方式
    JVM参数
  • 原文地址:https://www.cnblogs.com/misty1/p/2636926.html
Copyright © 2011-2022 走看看