• Apple Tree (POJ2486


                          题目传送门

     题解:

      第一道树上背包题qaq

      考虑每个节点在最终答案中的类型:1,不经过;2,经过但不返回;3,经过且返回 (返回的定义是最终的停止节点不位于该节点的子树中)

      对于第一种类型的节点,不用考虑。

      对于后两种类型,我们设f[i][j][0]表示在第i个节点的子树中走j步且最终回到i节点所能够获得的最大权值,f[i][j][1]表示最终不回到i节点获得的最大权值。

      对于一个节点的每一个子节点,都要选择其中的一种状态。我们可以把该问题抽象成分组背包问题:一个容量为j的背包,有siz组物品(siz相当于子节点数目),每组物品只能选一种。那么我们可以得到状态转移方程: 

      f[i][j][0] = max{f[v][k][0]+f[i][j-k-2][0]} (既然要回到该节点,那么对于子节点v来说肯定也要回到v节点,且下去上来各一步,故多用掉两步)

      f[i][j][1] = max{f[v][k][0]+f[i][j-k-2][1]} (对于v节点来说,下去不回来,那么其他的节点下去后就必须回来)

      f[i][j][1] = max{f[v][k][1]+f[i][j-k-1][0]} (该节点回来,那么其他节点可以不回来)

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #define LL long long
     5 #define RI register int
     6 using namespace std;
     7 const int INF = 0x7ffffff ;
     8 const int N = 100 + 10 ;
     9 const int K = 200 + 10 ;
    10 
    11 inline int read() {
    12     int k = 0 , f = 1 ; char c = getchar() ;
    13     for( ; !isdigit(c) ; c = getchar())
    14       if(c == '-') f = -1 ;
    15     for( ; isdigit(c) ; c = getchar())
    16       k = k*10 + c-'0' ;
    17     return k*f ;
    18 }
    19 
    20 struct Edge {
    21     int to, next ;
    22 }e[N<<1] ;
    23 int n, k, cnt = 0 ; int head[N], w[N], f[N][K][2] ;  // 0表示回来,1表示不回来 
    24 inline void add_edge(int x,int y) {
    25     e[++cnt].to = y, e[cnt].next = head[x], head[x] = cnt ;
    26 }
    27 
    28 void dfs(int x,int fa) {
    29     for(int j=0;j<=k;j++) f[x][j][0] = f[x][j][1] = w[x] ;
    30     for(int i=head[x];i;i=e[i].next) {
    31         int y = e[i].to ; if(y == fa) continue ;
    32         dfs(y,x) ;
    33         for(int j=k;j>=0;j--) {
    34             for(int kk=0;kk<=j;kk++) {
    35                 if(j >= kk+2) f[x][j][0] = max(f[x][j][0],f[x][j-kk-2][0]+f[y][kk][0]) ;
    36                 if(j >= kk+2) f[x][j][1] = max(f[x][j][1],f[x][j-kk-2][1]+f[y][kk][0]) ;
    37                 if(j >= kk+1) f[x][j][1] = max(f[x][j][1],f[x][j-kk-1][0]+f[y][kk][1]) ;
    38             }
    39         }
    40     }
    41 }
    42 
    43 int main() {
    44     while(~scanf("%d %d",&n,&k)) {
    45         cnt = 0 ; memset(head,0,sizeof(head)) ;
    46         for(int i=1;i<=n;i++) w[i] = read() ;
    47         for(int i=1;i<n;i++) {
    48             int x = read(), y = read() ;
    49             add_edge(x,y) ; add_edge(y,x) ;
    50         }
    51         dfs(1,0) ;
    52         printf("%d
    ",max(f[1][k][0],f[1][k][1])) ;
    53      }
    54      return 0 ;
    55 }

       第一次就错在了子节点中只能有一个下去不回来qwq

  • 相关阅读:
    转:Nginx 日志文件切割
    nginx日志切割
    nginx日志配置
    Mongodb数据更新命令
    Android开发书籍推荐
    全面解读python web 程序的9种部署方式
    PowerDesinger15设置字体大小
    A* Pathfinding Project (Unity A*寻路插件) 使用教程
    jQuery的DOM操作之捕获和设置
    如何写一个好的方法
  • 原文地址:https://www.cnblogs.com/zub23333/p/8758891.html
Copyright © 2020-2023  润新知