zoukankan      html  css  js  c++  java
  • 树形dp1

    选择结点: dp[ i ] [ 0 / 1]

    树上背包:f[ v ] [ k ] =f[ u ] [ k ]+ val;

           f [ u ] [ k ]= max( f[v ][k-1],f[u][k]) 

    常规:f[ i ] [ j ],以i为根的结点。。。

    http://acm.hdu.edu.cn/showproblem.php?pid=1520

    感觉被坑辽,我没看到有多组数据输入欸。

    f[ u ][ 0 ] 表示u结点不去,f[ u ] [ 1 ]表示去;

    u不去的话,子结点可去可不去;

    u去的话,子结点必须去;

    注意初始化,以及找根节点。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=6010;
     4 const int inf=0x3f;
     5 int head[maxn],f[maxn][2],cnt,v1[maxn],vis[maxn];
     6 struct edge{
     7     int nx,to,val;
     8 }edge[maxn*2];
     9 void add(int u,int v)
    10 {
    11     edge[++cnt].nx=head[u];
    12     edge[cnt].to=v;
    13     head[u]=cnt;
    14 }
    15 void dfs(int x)
    16 {
    17     f[x][1]=v1[x];vis[x]=1;
    18     for(int i=head[x];i;i=edge[i].nx)
    19     {
    20         int v=edge[i].to,w=v1[x];
    21         if(!vis[v]){
    22             dfs(v);
    23             f[x][1]+=f[v][0];
    24             f[x][0]+=max(f[v][0],f[v][1]);
    25         }
    26     }
    27 }
    28 signed main()
    29 {
    30     int n;
    31     while(scanf("%d",&n)!=EOF){
    32         memset(v1,0,sizeof(v1));
    33         memset(vis,0,sizeof(vis));
    34         memset(edge,0,sizeof(edge));
    35         memset(head,0,sizeof(head));
    36         cnt=0;
    37         for(int i=1;i<=n;i++) cin>>v1[i];
    38         int u,v;
    39         memset(f,0,sizeof(f));
    40         while((scanf("%d %d",&u,&v),u||v))
    41         {
    42             add(u,v);add(v,u);
    43             vis[v]=1;
    44         }
    45         for(int i=1;i<=n;i++)
    46         {
    47             if(!vis[i]){//找到根节点
    48                 memset(vis,0,sizeof(vis));
    49                 dfs(i);
    50                 cout<<max(f[i][1],f[i][0])<<endl;
    51                 break;
    52             }
    53         }
    54     }
    55 }
    View Code

    http://acm.hdu.edu.cn/showproblem.php?pid=2196

    树上背包:

    这类问题就是让你求在树上选一些点满足价值最大的问题,一般都可以设f[i][j]表示i这颗子树选j个点的最优解。

    P2014 [CTSC1997]选课

    https://www.luogu.com.cn/problem/P2014

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=400;
     4 int head[maxn],n,m,val[maxn],cnt,f[maxn][maxn];
     5 struct edge
     6 {
     7     int nx,to;
     8 }edge[maxn*2];
     9 void add(int u,int v)
    10 {
    11     edge[++cnt].nx=head[u];
    12     edge[cnt].to=v;
    13     head[u]=cnt;
    14 }
    15 void dfs(int x,int fa)
    16 {
    17     f[x][1]=val[x];
    18     for(int i=head[x];i;i=edge[i].nx)
    19     {
    20         int v=edge[i].to;
    21         if(v!=fa){
    22             dfs(v,x);
    23             for(int j=m;j>=0;j--)//树上背包,j为一共选择的结点数
    24             {
    25                 for(int k=0;k<j;k++)//k为子结点选择孙子结点数,j-k则为选择的子结点数
    26                     f[x][j]=max(f[x][j],f[x][j-k]+f[v][k]);
    27             }
    28         }
    29     }
    30 }
    31 int main()
    32 {
    33     cin>>n>>m;
    34     for(int i=1;i<=n;i++)
    35     {
    36         int k;
    37         cin>>k>>val[i];
    38         add(k,i),add(i,k);
    39     }
    40     m++;
    41     dfs(0,-1);//设置一个虚根0
    42     cout<<f[0][m]<<endl;
    43 }
    View Code

    https://www.luogu.com.cn/problem/P2015

    转化一下,将边权变为点权;

    树上背包模板题;

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=400;
     4 int head[maxn],n,m,val[maxn],cnt,f[maxn][maxn];
     5 struct edge
     6 {
     7     int nx,to,w;
     8 }edge[maxn*2];
     9 void add(int u,int v)
    10 {
    11     edge[++cnt].nx=head[u];
    12     edge[cnt].to=v;
    13     head[u]=cnt;
    14 }
    15 void dfs(int x,int fa)
    16 {
    17     f[x][1]=val[x];
    18     for(int i=head[x];i;i=edge[i].nx)
    19     {
    20         int v=edge[i].to;
    21         if(v!=fa){
    22             dfs(v,x);
    23             for(int j=m;j>0;j--)
    24             {
    25                 for(int k=0;k<j;k++)
    26                     f[x][j]=max(f[x][j],f[x][j-k]+f[v][k]);
    27             }
    28         }
    29     }
    30 }
    31 int main()
    32 {
    33     cin>>n>>m;
    34     for(int i=1;i<n;i++)
    35     {
    36         int k,b,s;
    37         cin>>k>>b>>s;
    38         if(!val[b]) val[b]=s;//因为给的点不确定是子结点还是父节点,则建立双向边,每个节点只有一个权值
    39         else val[k]=s;
    40         add(k,b),add(b,k);
    41     }
    42     m++;
    43     dfs(1,0);
    44     cout<<f[1][m]<<endl;
    45 }
    View Code
  • 相关阅读:
    JDK动态代理源码解析
    Drools规则引擎-判断集合(List)是否包含集合
    Drools规则引擎-memberOf操作
    我对于今目标的反思
    UltraEdit的配置
    演讲的注意事项
    原型的安装及使用
    java异常的一些小知识
    网络攻击技术开篇——SQL Injection
    机房重构之接口
  • 原文地址:https://www.cnblogs.com/Showend/p/13258244.html
Copyright © 2011-2022 走看看