• 树形dp--P1273 有线电视网


    *传送

    *定义状态:
    这道题是一道裸的树形背包题,设$f[i][j]$表示以$i$ 为根往下找$j$ 个叶子的最大价值,那么答案就是所有$f[1][j]≥0$当中最大的$j$。
    在dp之前,我们按照后序遍历序列重新编号(即遍历到一个节点时,先搜索节点的子树,为它们编号后再为这个节点编号)。
    然后开始dp,首先初始化,对$f[i][j]$赋值−$INF$,当$j==0$ 时$f[i][j]=0$ 。

    *状态转移:
    如果i$$点是叶子节点那么有$f[i][j]=max(f[i−1][j−1]+c[i],f[i−1][j])$ 和一般的0/1背包没什么区别
    如果不是的话,如果我们取$i$的话$f[i][j]=f[i−1][j]+c[i]$,但是如果不取的话它和它的子树就一个都不能取了。
    而由后序遍历定义不难推出$i$的子树节点编号在$[i−sz[i]+1,i]$之间($sz[i]$为子树i的大小)。
    所以不取的话$f[i][j]=f[i−sz[i]][j]$ ,综上$f[i][j]=max(f[i−1][j]+c[i],f[i−sz[i]][j])$
    代码:

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 const int N=6000;
     5 const int INF=1e9;
     6 using namespace std;
     7 int read(){
     8     int x = 1,a = 0;
     9     char ch = getchar();
    10     while(ch < '0' || ch > '9'){
    11         if(ch == '-')x = -1;
    12         ch = getchar();
    13     }
    14      while(ch <= '9'&&ch >= '0'){
    15         a = a * 10 + ch - '0';
    16         ch = getchar();
    17     }
    18     return x*a;
    19 }
    20 struct node{
    21     int to,next;
    22 }ed[N];
    23 int n,m,head[N],tot;
    24 void add(int u,int v){//链前 
    25     ed[++tot].next=head[u];
    26     ed[tot].to=v;
    27     head[u]=tot;
    28 }
    29 int f[N][N],sz[N],idx[N],cnt,c[N];
    30 void dfs(int x){
    31     sz[x]=1;
    32     for (int i = head[x];i;i=ed[i].next){
    33         int v=ed[i].to;
    34         dfs(v);sz[x]+=sz[v]; //求子树大小 
    35     }
    36     idx[++cnt]=x;//遍历顺序 
    37 }
    38 int main(){
    39     scanf ("%d%d",&n,&m);
    40     for(int i=1;i<=n-m;i++){
    41         int k=read();
    42         for(int j=1;j<=k;j++){
    43             int v=read();c[v]=-read();// 花费为负 
    44             add(i,v);//构建树,转播站和能转播到的节点连在一起 
    45         }
    46     }
    47     for(int i=n-m+1;i<=n;i++)c[i]+=read();// 预算为正 
    48     dfs(1);
    49     for(int i=0;i<=cnt;i++)
    50         for(int j=1;j<=m;j++)
    51             f[i][j]=-INF;
    52     for(int i=1;i<=cnt;i++){
    53         int u=idx[i];
    54         for(int j=1;j<=m;j++){
    55             if(n-m+1<=u)f[i][j]=max(f[i-1][j-1]+c[u],f[i-1][j]);// 是客户(叶子)节点 
    56             else f[i][j]=max(f[i-1][j]+c[u],f[i-sz[u]][j]); // 不是客户(叶子)节点 
    57         }
    58     }
    59     for(int i=m;i>=0;i--){
    60         if(f[cnt][i]>=0){
    61             printf("%d
    ",i);return 0;
    62         }
    63     }
    64     return 0;
    65 }
  • 相关阅读:
    Pascal's Triangle II
    Pascal's Triangle
    Path Sum II
    Path Sum
    plusOne
    Divide Two Integers
    64. ZigZag Conversion
    63. Swap Nodes in Pairs && Rotate List && Remove Nth Node From End of List
    62. Divide Two Integers
    61. Unique Paths && Unique Paths II
  • 原文地址:https://www.cnblogs.com/very-beginning/p/12651552.html
Copyright © 2020-2023  润新知