zoukankan      html  css  js  c++  java
  • 【CTSC1997】选课

    树形dp可能是最优美的dp了……

    这是一道经典的树上背包问题,考虑两种做法。第一种是直接在树上做一遍背包问题,另一种是把这棵树转化成“左儿子右兄弟”的二叉树,再做一遍背包问题。

    方法一:我们定义f[i][j]表示以i为根的子树,一共选j门课最大的分数,那么我们可以得到f[i][j]=max(f[i][j-k]+f[x][k]) 其中x∈son(i).将这棵树遍历一遍即可求解。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <vector>
     5 using namespace std;
     6 int n,m,s[310];
     7 vector<int> a[310];
     8 int f[310][310];
     9 void dfs(int now) {
    10     f[now][0]=0;
    11     for(int i=0;i<a[now].size();i++) {
    12         int to=a[now][i];
    13         dfs(to);
    14         for(int j=m;j>=0;j--)
    15             for(int k=j;k>=0;k--)
    16                 f[now][j]=max(f[now][j],f[now][j-k]+f[to][k]);
    17     }
    18     if(now) {
    19         for(int i=m;i>=1;i--) 
    20             f[now][i]=f[now][i-1]+s[now];
    21     }
    22 }
    23 int main() {
    24     cin>>n>>m;
    25     for(int i=1,x;i<=n;i++) {
    26         cin>>x>>s[i];
    27         a[x].push_back(i);
    28     }
    29     memset(f,0xcf,sizeof(f));
    30     dfs(0);
    31     cout<<f[0][m]<<endl;
    32     return 0;
    33 }
    AC Code 1

    方法二:将这棵树转化为“左儿子右兄弟”的二叉树,此时f[i][j]表示在新的二叉树当中,f[i][j]表示以i为根的子树,一共选j门课最大的分数。那么分两种情况讨论。

    1. 如果不选i,那么i的左儿子(原来的树中的儿子)就不能选,此时f[i][j]=f[brother[i]][j].
    2. 如果选i,并且选了k个i的左儿子,那么f[i][j]=val[i]+f[son[i]][k]+f[brother[i]][j-k-1].

    我们在这两种决策当中取最优即可。

     1 #include <cstdio>
     2 #include <cstring>
     3 using namespace std;
     4 template <typename T>
     5 T max(T x,T y)
     6 {
     7     return x>y?x:y;
     8 }
     9 inline int read() {
    10     int ret=0,f=1;
    11     char c=getchar();
    12     while(c<'0'||c>'9') {
    13         if(c=='-') f=-1;
    14         c=getchar();
    15     }
    16     while(c<='9'&&c>='0') {
    17         ret=ret*10+c-'0';
    18         c=getchar();
    19     }
    20     return ret*f;
    21 }
    22 int n,m,so[310],br[310];
    23 int f[310][310],val[310];
    24 inline void add(int father,int son) {
    25     br[son]=so[father];
    26     so[father]=son;
    27 }
    28 int dfs(int i,int j) {
    29     if(i==-1) return 0;
    30     if(j==0) return 0;
    31     if(f[i][j]!=-1) return f[i][j];
    32     int ret=-1<<30;
    33     ret=max(ret,dfs(br[i],j));
    34     for(int k=0;k<=j-1;k++)
    35         ret=max(ret,dfs(so[i],k)+dfs(br[i],j-k-1)+val[i]);
    36     return f[i][j]=ret;
    37 }
    38 int main() {
    39     n=read(); m=read();
    40     memset(so,-1,sizeof(so));
    41     memset(br,-1,sizeof(br));
    42     memset(f,-1,sizeof(f));
    43     for(int i=1;i<=n;i++) {
    44         int x;
    45         x=read();
    46         val[i]=read();
    47         add(x,i);
    48     }
    49     printf("%d
    ",dfs(0,m+1));
    50     return 0;
    51 }
    AC Code 2
  • 相关阅读:
    SQL EXPLAIN优化详解
    2019数据智能算法大赛赛后复盘
    K-D树详解
    点云配准相关
    pandas速查手册(中文版)
    Windows CMD命令大全
    获取时间戳
    SQL 字符串转成临时表
    delphi cxgrid明细新增第三行的报错【Key violation】
    cxgrid列的Properties(cxPopupEditPopup)的关闭方法
  • 原文地址:https://www.cnblogs.com/shl-blog/p/10700674.html
Copyright © 2011-2022 走看看