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;
    }
  • 相关阅读:
    常见二叉树问题
    leetcode上回溯法的使用
    搜索+回溯
    navicat连接登录windows10本地wsl的数据库
    皇后问题
    拓扑排序
    三路排序算法
    在 ServiceModel 客户端配置部分中,找不到引用协定“WebServiceTest.WebServiceSoap”的默认终结点元素。这可能是因为未找到应用程序的配置文件,或者是因为客户端元素
    WCF异常信息
    C# 制作ZIP压缩包
  • 原文地址:https://www.cnblogs.com/chenhuan001/p/3078619.html
Copyright © 2011-2022 走看看