zoukankan      html  css  js  c++  java
  • poj 2486(树形DP+背包)

    其实就是以dfs的顺序进行背包处理. 想了快一天,终于1A了, 但是虽然过了,但是心里还是有点虚,可能对背包的原理没有透彻掌握,所以宏观上看是可行的,但是一想到一步一步的具体转移时又会觉得很混乱.  

    一、首先这种题要做的是确定状态, 每个结点要记录什么状态 ?  这题根据题意要记录的是 1. 从这个结点u开始不到达u以上的结点但是最后回到u结点经过的最大权 记为dp[u][k]    2. 从这个结点u开始不到达u以上的结点最后不必回到u经过的最大权 记为dp1[u][k]

    二、有了这两个条件就可以进行状态转移了。  假设当前结点为u, u的子结点为 vi

    那么从u结点出发最后回到u结点的所有情况为 dp1[u][k] ,k=0,2,4...

    这样整体想就可以知道, 我是否可以通过经过vi这个子树,使得dp1[u][k] 变大 

    for(int i=k;i>=0;i--)
      for(int j=0;j<=k;j++) // 用子树 dp1[vi][j],0=< j <=k 的情况更新每个 dp1[u][i]  i>=0,i<=k. 
      {
        if( i-2-j >= 0 ) // 为什么要减2,因为到子树又返回需要多于消耗2次操作
          dp1[s][i]=max( dp1[s][i] , dp1[s][i-2-j] + dp1[vi][j] );
      }

    从u结点出发但是最后不会到u的所以情况 dp[u][k]  , k=0,1,2,3... (这个也是我们要求得最终答案)

    这层状态需要用到dp1[vi][] 和 dp[vi][] 一起

    for(int i=k;i>=0;i--)
        for(int j=0;j<=k;j++)
        {
            if( i-2-j >= 0 ) dp[u][i]=max(dp[u][i],dp[u][i-2-j]+dp1[vi][j]); // 
            if( i-1-j >= 0 ) dp[u][i]=max(dp[u][i],dp1[u][i-1-j]+dp[vi][j]);
        }    

    三、 确定初始状态

    显而易见的是,每个点在最开始的状态都是这个点自身的权值。 

    for(int j=0;j<=k;j++)
        dp[i][j]=dp1[i][j]=wi;
    Apple Tree
    Time Limit: 1000MS   Memory Limit: 65536K
    Total Submissions: 6019   Accepted: 1941

    Description

    Wshxzt is a lovely girl. She likes apple very much. One day HX takes her to an apple tree. There are N nodes in the tree. Each node has an amount of apples. Wshxzt starts her happy trip at one node. She can eat up all the apples in the nodes she reaches. HX is a kind guy. He knows that eating too many can make the lovely girl become fat. So he doesn’t allow Wshxzt to go more than K steps in the tree. It costs one step when she goes from one node to another adjacent node. Wshxzt likes apple very much. So she wants to eat as many as she can. Can you tell how many apples she can eat in at most K steps.

    Input

    There are several test cases in the input 
    Each test case contains three parts. 
    The first part is two numbers N K, whose meanings we have talked about just now. We denote the nodes by 1 2 ... N. Since it is a tree, each node can reach any other in only one route. (1<=N<=100, 0<=K<=200) 
    The second part contains N integers (All integers are nonnegative and not bigger than 1000). The ith number is the amount of apples in Node i. 
    The third part contains N-1 line. There are two numbers A,B in each line, meaning that Node A and Node B are adjacent. 
    Input will be ended by the end of file. 

    Note: Wshxzt starts at Node 1.

    Output

    For each test case, output the maximal numbers of apples Wshxzt can eat at a line.

    Sample Input

    2 1 
    0 11
    1 2
    3 2
    0 1 2
    1 2
    1 3
    

    Sample Output

    11
    2
    

    Source

    POJ Contest,Author:magicpig@ZSU
    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    using namespace std;
    
    int dp[110][220],dp1[110][220];
    int n,k;
    int mark[110];
    int g[110][110];
    
    void dfs(int s)
    {
        mark[s]=1;
        for(int i=1;i<=n;i++)
        {
            if(g[s][i]==0||mark[i]==1) continue;
            dfs(i);
            for(int j=k;j>=0;j--)
            {
                for(int i1=0;i1<=k;i1++)
                {
                    if( j-2-i1 < 0 ) continue;
                    dp1[s][j] = max(dp1[s][j],dp1[ s ][ j-2-i1 ] + dp1[i][i1]);
                }
                for(int i1=0;i1<=k;i1++)
                {
                    if(j-2-i1 >= 0) dp[s][j]=max(dp[s][j],dp[s][j-2-i1]+dp1[i][i1]);
                    if(j-1-i1 >= 0) dp[s][j]=max(dp[s][j],dp1[s][j-1-i1]+dp[i][i1]);
                }
            }
        }
    }
    
    int main()
    {
        while(scanf("%d%d",&n,&k)!=EOF)
        {
            memset(dp,0,sizeof(dp));
            memset(dp1,0,sizeof(dp1));
            for(int i=1;i<=n;i++)
            {
                int tmp;
                scanf("%d",&tmp);
                for(int j=0;j<=k;j++)
                dp[i][j]=dp1[i][j]=tmp;
            }
            memset(g,0,sizeof(g));
            for(int i=1;i<n;i++)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                g[x][y]=g[y][x]=1;
            }
            memset(mark,0,sizeof(mark));
            dfs(1);
            printf("%d\n",dp[1][k]);
        }
        return 0;
    }
  • 相关阅读:
    分布式
    jdk与jre的区别
    rabbitmq
    dicom错误解决
    centos6.5搭建hadoop完整教程
    spark
    Oracle索引扫描
    Oracle的rowid结构解析
    PL/SQL — 集合及常用方法
    PL/SQL — 变长数组
  • 原文地址:https://www.cnblogs.com/chenhuan001/p/3078619.html
Copyright © 2011-2022 走看看