zoukankan      html  css  js  c++  java
  • 树形DP专题

    hdu 1520  Anniversary party

    分析:要求不跟自己的上司或下属在一起即根不与其孩子同时选择。

    dp[i][0]表示i为根且根不选获得的最大值,则其值为孩子结点选择与不选的最大值

    即dp[i][0]=max(dp[son][0],dp[son][1]);

    dp[i][1]表示i为根且选择获得的最大值,则其孩子结点不能选择dp[i][1]=sum{dp[son][0]};

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #define maxlen 6010
     5 using namespace std;
     6 struct node
     7 {
     8     int to,next,w;
     9 }edge[maxlen*2];
    10 int head[maxlen];
    11 int num;
    12 int dp[maxlen][2];
    13 bool used[maxlen];
    14 int c[maxlen];
    15 void init()
    16 {
    17     num=0;
    18     memset(head,-1,sizeof(head));
    19     memset(used,false,sizeof(used));
    20     memset(dp,0,sizeof(dp));
    21     memset(c,0,sizeof(c));
    22 }
    23 void addedge(int u,int v,int w)
    24 {
    25     edge[num].to=v;
    26     edge[num].w=w;
    27     edge[num].next=head[u];
    28     head[u]=num++;
    29     edge[num].to=u;
    30     edge[num].w=w;
    31     edge[num].next=head[v];
    32     head[v]=num++;
    33 }
    34 void dfs(int u)
    35 {
    36     if(used[u])
    37         return ;
    38     used[u]=true;
    39     dp[u][1]=c[u];
    40     for(int i=head[u];i!=-1;i=edge[i].next)
    41     {
    42         int v=edge[i].to;
    43         if(!used[v])
    44         {
    45             dfs(v);
    46             dp[u][0]+=max(dp[v][0],dp[v][1]);
    47             dp[u][1]+=dp[v][0];
    48         }
    49     }
    50 }
    51 int main ()
    52 {
    53     int n,x,y;
    54     while(scanf("%d",&n)!=EOF)
    55     {
    56         init();
    57         for(int i=1;i<=n;++i)
    58             scanf("%d",&c[i]);
    59         while(scanf("%d%d",&x,&y))
    60         {
    61             if(x==0&&y==0)
    62                 break;
    63             addedge(x,y,0);
    64         }
    65         dfs(1);
    66         int ans=max(dp[1][0],dp[1][1]);
    67         printf("%d
    ",ans);
    68     }
    69 }
    View Code

    hdu 1561 The more, The Better

     增加一个权值为0的0号节点使整个成为一棵树,接下来就是0-1背包的问题了

    dp[u][j]表示u为根节点选择j个获得的最大价值,根节点必须选择,然后其他可以

    从孩子节点中选择。

    dp[u][j]=max{dp[u][j],dp[son][j-k]+dp[u][k]}

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #define maxlen 210
     5 using namespace std;
     6 bool used[maxlen];
     7 int cost[maxlen];
     8 int maps[maxlen][maxlen];
     9 int num[maxlen];
    10 int dp[maxlen][maxlen];
    11 int n,m;
    12 void dfs(int x)
    13 {
    14     used[x]=true;
    15     for(int i=1;i<=num[x];++i)
    16     {
    17         int u=maps[x][i];
    18         if(!used[u])
    19             dfs(u);
    20         for(int j=m;j>=2;--j)
    21         {
    22             for(int k=1;k<j;++k)
    23             {
    24                 if(dp[x][k]!=-1&&dp[u][j-k]!=-1&&used[u])
    25                 dp[x][j]=max(dp[x][j],dp[x][k]+dp[u][j-k]);
    26             }
    27         }
    28     }
    29 
    30 }
    31 int main ()
    32 {
    33     while(scanf("%d%d",&n,&m)!=EOF)
    34     {
    35         if(n==0&&m==0)
    36             break;
    37         m++;//添加一个编号为0权值为0的点,这个顶点必须选
    38         dp[0][1]=cost[0]=0;
    39         memset(maps,0,sizeof(maps));
    40         memset(num,0,sizeof(num));
    41         memset(used,0,sizeof(used));
    42         for(int i=1;i<=n;++i)
    43         {
    44             int x,y;
    45             scanf("%d%d",&x,&y);
    46             maps[x][++num[x]]=i;
    47             cost[i]=y;
    48         }
    49         for(int i=0;i<=n;++i)
    50         {
    51             dp[i][0]=0;
    52             dp[i][1]=cost[i];
    53             for(int j=2;j<=m;++j)
    54             {
    55                 dp[i][j]=-1;
    56             }
    57         }
    58         dfs(0);
    59         printf("%d
    ",dp[0][m]);
    60     }
    61 }
    View Code

    hdu 2196 Computer

    要求输出对于每一个结点的树上任意结点到该点的最大距离。

    需要两次dfs,第一次dfs是更新该结点的孩子结点到它的距离,需要记录最大值以及次大值。

    另一个dfs是更新从父节点过来的最大值,之所以需要记录次小值是因为如果只存最大值的话,

    判断一个点的从父节点过来的最大值,那么如果他的父节点存的最大值正好是从该点过来的,

    那么就失去了从父节点过来的状态,所以要记录最大的两个值。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #define maxlen 10010
      6 using namespace std;
      7 struct node
      8 {
      9     int to,next,w;
     10 }edge[maxlen*2];
     11 int head[maxlen];
     12 int num;
     13 int maxnum[maxlen];
     14 int smaxnum[maxlen];
     15 int maxid[maxlen];
     16 int smaxid[maxlen];
     17 void init()
     18 {
     19     num=0;
     20     memset(head,-1,sizeof(head));
     21 }
     22 void addedge(int u,int v,int w)
     23 {
     24     edge[num].to=v;
     25     edge[num].w=w;
     26     edge[num].next=head[u];
     27     head[u]=num++;
     28     edge[num].to=u;
     29     edge[num].w=w;
     30     edge[num].next=head[v];
     31     head[v]=num++;
     32 }
     33 void dfs(int u,int father)
     34 {
     35     maxnum[u]=smaxnum[u]=0;
     36     for(int i=head[u];i!=-1;i=edge[i].next)
     37     {
     38         int v= edge[i].to;
     39         if(v==father)
     40             continue;
     41         dfs(v,u);
     42         if(smaxnum[u]<maxnum[v]+edge[i].w)
     43         {
     44             smaxnum[u]=maxnum[v]+edge[i].w;
     45             smaxid[u]=v;
     46             if(smaxnum[u]>maxnum[u])
     47             {
     48                 swap(smaxnum[u],maxnum[u]);
     49                 swap(smaxid[u],maxid[u]);
     50             }
     51         }
     52     }
     53 }
     54 void dfs2(int u,int father)
     55 {
     56     for(int i=head[u];i!=-1;i=edge[i].next)
     57     {
     58         int v=edge[i].to;
     59         if(v==father)
     60             continue;
     61         //dfs2(v,u);
     62         if(v==maxid[u])
     63         {
     64             if(edge[i].w+smaxnum[u]>smaxnum[v])
     65             {
     66                 smaxnum[v]=edge[i].w+smaxnum[u];
     67                 smaxid[v]=u;
     68                 if(smaxnum[v]>maxnum[v])
     69                 {
     70                     swap(smaxnum[v],maxnum[v]);
     71                     swap(smaxid[v],maxid[v]);
     72                 }
     73             }
     74         }
     75         else
     76         {
     77             if(edge[i].w+maxnum[u]>smaxnum[v])
     78             {
     79                 smaxnum[v]=edge[i].w+maxnum[u];
     80                 smaxid[v] = u;
     81                 if(smaxnum[v]>maxnum[v])
     82                 {
     83                     swap(smaxnum[v],maxnum[v]);
     84                     swap(smaxid[v],maxid[v]);
     85                 }
     86             }
     87         }
     88         dfs2(v,u);
     89     }
     90 }
     91 int main ()
     92 {
     93     int n,v,w;
     94     while(scanf("%d",&n)!=EOF)
     95     {
     96         init();
     97         for(int i=2;i<=n;++i)
     98         {
     99             scanf("%d%d",&v,&w);
    100             addedge(i,v,w);
    101         }
    102         dfs(1,-1);
    103         dfs2(1,-1);
    104         for(int i=1;i<=n;++i)
    105             printf("%d
    ",maxnum[i]);
    106     }
    107 
    108 }
    View Code

    hdu 4276 The Ghost Blows Light  2012 ACM/ICPC Asia Regional Changchun Online

    分析:首先根据题目意思从1到n的路径是必须要走的,所以我们可以先求出1到n的最短路径然后把这条路径

    的权值改为0使接下来的dp一定会选择这些点。

    dp[u][j]表示u为根使用j的时间可以获得的最大值,由于最短的路径且这条路径走也只能走一次才能最短,

    所以其他的路径都是分支,走过去还是需要回来的,所以花费的时间w是单次的两遍(往返)

    方程为dp[u][j] = max{dp[u][j],dp[son][k]+dp[u][j-k-w]}  j>=k+w  

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #define maxlen 610
     5 using namespace std;
     6 struct node
     7 {
     8     int to,next,w;
     9 }edge[maxlen*2];
    10 int head[maxlen];
    11 int num;
    12 int n,t;
    13 int dp[maxlen][maxlen];
    14 int c[maxlen];
    15 bool used[maxlen];
    16 int sum;
    17 void init()
    18 {
    19     num=0;
    20     memset(head,-1,sizeof(head));
    21     memset(used,0,sizeof(used));
    22     memset(dp,0,sizeof(dp));
    23     memset(c,0,sizeof(c));
    24 }
    25 void addedge(int u,int v,int w)
    26 {
    27     edge[num].to=v;
    28     edge[num].w=w;
    29     edge[num].next=head[u];
    30     head[u]=num++;
    31     edge[num].to=u;
    32     edge[num].w=w;
    33     edge[num].next=head[v];
    34     head[v]=num++;
    35 }
    36 bool short_path(int u,int father)
    37 {
    38     if(u==n)
    39         return true;
    40     for(int i=head[u];i!=-1;i=edge[i].next)
    41     {
    42         int v=edge[i].to;
    43         if(v==father)
    44             continue;
    45         if(short_path(v,u))
    46         {
    47             sum+=edge[i].w;
    48             edge[i].w=0;
    49             return true;
    50         }
    51     }
    52     return false;
    53 }
    54 void dfs(int u,int father)
    55 {
    56     for(int i=0;i<=t;++i)
    57         dp[u][i]=c[u];
    58     for(int i=head[u];i!=-1;i=edge[i].next)
    59     {
    60         int v=edge[i].to;
    61         int w=edge[i].w*2;//还要返回主干的结点,所以时间是两倍
    62         if(v==father)
    63             continue;
    64         dfs(v,u);
    65         for(int j=t;j>=w;--j)
    66         {
    67             for(int k=0;k<=j-w;++k)
    68             {
    69                 dp[u][j]=max(dp[u][j],dp[v][k]+dp[u][j-w-k]);
    70             }
    71         }
    72     }
    73 }
    74 int main ()
    75 {
    76     while(scanf("%d%d",&n,&t)!=EOF)
    77     {
    78         init();
    79         for(int i=1;i<n;++i)
    80         {
    81             int x,y,w;
    82             scanf("%d%d%d",&x,&y,&w);
    83             addedge(x,y,w);
    84         }
    85         for(int i=1;i<=n;++i)
    86             scanf("%d",&c[i]);
    87         sum=0;
    88         short_path(1,-1);
    89         t-=sum;
    90         if(t<0)
    91             printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!
    ");
    92         else
    93         {
    94             dfs(1,-1);
    95             printf("%d
    ",dp[1][t]);
    96         }
    97 
    98     }
    99 }
    View Code
  • 相关阅读:
    java定义类 对象,引用,指针
    java数组 数组工具类Arrays
    java 流程执行 循环 foreach循环
    java注释 命名 数据类型 基本类型转换 位运算符 逻辑运算符 三目运算符
    maven 学习1 -安装maven 并执行编译命令
    Lucene工作原理(转)
    nginx&tomcat实现负载均衡
    nginx安装(centos-7下安装nginx-1.8.1)
    spring中bean的作用域
    Spring管理事务配置的五种方式
  • 原文地址:https://www.cnblogs.com/shuzy/p/3348840.html
Copyright © 2011-2022 走看看