zoukankan      html  css  js  c++  java
  • cogs 1199选课(树形dp 背包或多叉转二叉

    http://cogs.pro:8080/cogs/problem/problem.php?pid=vQyiJkkPP

    题意:给m门课,每门课在上完其先修课后才能上,要你从中选n门课使得总学分尽可能大。

    思路:背包,没有先修课看成其先修课编号为0,求一个f[0][n]的背包,表示以0为根的树选n个结点的最大总权值,设x为根,y为x的孩子,对每个孩子,dfs(y),然后f[[x][t]=max(f[x][t],f[x][t-j]+f[y][j])用每个孩子更新x,最后若x不是0,再用自己的权值更新自己。但背包好像不能记录路径。

     1 #include<bits/stdc++.h>
     2 #define rep(i,a,b) for(int i=a;i<=b;++i)
     3 #define dep(i,a,b) for(int i=a;i>=b;--i)
     4 using namespace std;
     5 const int MAXN=310;
     6 int read(){
     7     int sum=0,flag=1;
     8     char c;
     9     for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=-1;
    10     for(;c>='0'&&c<='9';c=getchar())sum=(sum<<1)+(sum<<3)+c-'0';
    11     return sum*flag;
    12 }
    13 int n,m;
    14 int v[MAXN];
    15 vector<int>son[MAXN];
    16 int f[MAXN][MAXN];
    17 void init(){
    18     n=read();m=read();
    19     rep(i,1,n){
    20         int y;
    21         y=read();v[i]=read();
    22         son[y].push_back(i);
    23     }
    24 }
    25 void DP(int x){
    26     f[x][0]=0;
    27     for(int i=0;i<son[x].size();++i){
    28         int y=son[x][i];
    29         DP(y);
    30         dep(t,m,0)
    31             dep(j,t,0)
    32                 if(t>=j)
    33                     f[x][t]=max(f[x][t],f[x][t-j]+f[y][j]);
    34     }
    35     if(x!=0) dep(t,m,1) f[x][t]=f[x][t-1]+v[x];
    36 }
    37 int main(){
    38     init();
    39     DP(0);
    40     printf("%d",f[0][m]);
    41     return 0;
    42 }
    View Code

    多叉转二叉,左孩子右兄弟。

    若选根结点,f[i][j] = f[br[i][j]

    若不选根结点,f[i][j] = f[ch[i]][k]+f[br[i]][j-1-k]+v[i]

    递归寻找路径方法类似。

     1 #include<bits/stdc++.h>
     2 #define rep(i,a,b) for(int i=a;i<=b;++i)
     3 #define dep(i,a,b) for(int i=a;i>=b;--i)
     4 using namespace std;
     5 const int MAXN=510;
     6 int read(){
     7     int sum=0,flag=1;
     8     char c;
     9     for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=-1;
    10     for(;c>='0'&&c<='9';c=getchar())sum=(sum<<1)+(sum<<3)+c-'0';
    11     return sum*flag;
    12 }
    13 int n,m;
    14 int v[MAXN];
    15 int br[MAXN],ch[MAXN];
    16 bool ans[MAXN];
    17 int f[MAXN][MAXN];
    18 void init(){
    19     n=read();m=read();
    20     int x;
    21     rep(i,1,n){
    22         x=read();
    23         v[i]=read();
    24         if(!x) x=n+1;
    25         br[i]=ch[x];
    26         ch[x]=i;
    27     }
    28     memset(f,-1,sizeof f);
    29 }
    30 void DP(int x,int y){
    31     if(f[x][y]>=0) return;
    32     if(!x||!y) {f[x][y]=0;return;}
    33     DP(br[x],y);
    34     rep(i,0,y-1){
    35         DP(br[x],i);
    36         DP(ch[x],y-i-1);
    37         f[x][y]=max(f[x][y],max(f[br[x]][y],f[br[x]][i]+f[ch[x]][y-i-1]+v[x]));
    38     }
    39 }
    40 void path(int x,int y){
    41     if(!x||!y) return;
    42     if(f[x][y]==f[br[x]][y]) path(br[x],y);
    43     else {
    44         rep(i,0,y-1){
    45             if(f[x][y]==f[br[x]][i]+f[ch[x]][y-i-1]+v[x]){
    46                 path(br[x],i);
    47                 path(ch[x],y-i-1);
    48                 ans[x]=1;
    49                 return;
    50             }
    51         }
    52     }
    53 }
    54 int main(){
    55     init();
    56     DP(ch[n+1],m);
    57     printf("%d
    ",f[ch[n+1]][m]);
    58     path(ch[n+1],m);
    59     rep(i,1,n) if(ans[i]) printf("%d
    ",i);
    60     return 0;
    61 }
    View Code

  • 相关阅读:
    1649. 超级棒棒糖
    1872. 连接棒材的最低费用
    二叉树的层级遍历转换
    ZMQ的三种消息模式
    logging日志
    Svn基本使用
    Pycharm快捷键
    Redis安装和连接
    整形转中文
    C# Socket连接 无法访问已释放的对象
  • 原文地址:https://www.cnblogs.com/wzgg/p/11393965.html
Copyright © 2011-2022 走看看