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 ;
    }
  • 相关阅读:
    用Eclipse+MyEclipse开发struts的一个经典的实例(转)
    TOMCAT配置虚拟目录
    翻动100万级的数据(自定义的MSSQL分页查询过程)
    MyEclipse Hibernate 快速入门中文版
    微软提供的数据访问组件SqlHelper
    Java内存管理(一、内存分配)
    使用commonlogging与log4j打印日志,发现版本冲突
    Java内存管理(二、Java垃圾回收)
    初探java内存机制_堆和栈
    关于单CPU,多CPU上的原子操作
  • 原文地址:https://www.cnblogs.com/misty1/p/2636926.html
Copyright © 2011-2022 走看看