zoukankan      html  css  js  c++  java
  • 有关树形背包

      背包是一种简单的DP,把它放在树上就不简单了。

      树形背包初级的做法:

        设f[i][j]是以i节点为根,体积为i的最大收益。 其实原来是f[u][i][j]表示以u为根,选取i个子树,体积为j的最大收益,但通过体积那一维的倒序循环(像01背包一样)可以在空间上优化为O(n^2),但时间上仍很庞大,为O(n^3)。

        f[i][j]=max(f[i][j],f[i][j-k]+f[v][k])       (循环j倒序,k从0到j。) 

          答案为f[根][背包体积]

      于是就有了优化:

        设f[i][j]表示dfs序从i到tot,体积为j的最大价值。

        先dfs一遍,计算每棵子树的siz【】,对每一个dfs序建立与原编号的映射,(id[++num]=x).

        f[i][j]=max(f[i+siz[i]][j],f[i+1][j-w[i]]+val[i])       (循环i倒序)

          答案为f[1]【背包体积】

      还有别的优化,但是我不会。。。

       以下是代码:

         例题     luoguP2515 [HAOI2010]软件安装

     1 #include<bits/stdc++.h>
     2 #define ll long long
     3 #define RE register
     4 using namespace std;
     5 const int maxn=2200;
     6 inline int R(){
     7     RE char b=getchar();int x=0,t=1;
     8     while(b<'0'||b>'9'){if(b=='-') t=-1;b=getchar();}
     9     while(b>='0'&&b<='9') {x=(x<<3)+(x<<1)+b-'0';b=getchar();}
    10     return x*t;
    11 }
    12 struct Edge{
    13     int nxt,to;
    14 }ed[maxn];
    15 int head[maxn],ecnt;
    16 void addedge(int f,int to){
    17     ed[++ecnt].to=to;
    18     ed[ecnt].nxt=head[f];
    19     head[f]=ecnt;
    20 }
    21 int n,m;
    22 int w[maxn],v[maxn],d[maxn];
    23 int ww[maxn],vv[maxn],rd[maxn];
    24 int siz[maxn];
    25 int f[maxn][maxn];
    26 void dfs(int x){// 划重点
    27     for(int i=ww[x];i<=m;i++) f[x][i]=vv[x];
    28 //    f[x][ww[x]]=vv[x];
    29     for(int i=head[x];i;i=ed[i].nxt){
    30         int v=ed[i].to;
    31         dfs(v);
    32         for(int j=m-ww[x];j>=0;j--) for(int k=0;k<=j;k++){
    33             f[x][j+ww[x]]=max(f[x][j+ww[x]],f[x][j+ww[x]-k]+f[v][k]);
    34         }
    35     }
    36 }
    37 int dfn[maxn],low[maxn],num;
    38 bool vis[maxn];
    39 int sta[maxn],tp;
    40 int scc_num,scc[maxn];
    41 void tarjan(int x){
    42     sta[++tp]=x;
    43     vis[x]=1;
    44     dfn[x]=low[x]=++num;
    45     for(int i=head[x];i;i=ed[i].nxt){
    46         int v=ed[i].to;
    47         if(!dfn[v]){
    48             tarjan(v);
    49             low[x]=min(low[x],low[v]);
    50         }
    51         else if(vis[v]) low[x]=min(low[x],dfn[v]);
    52     }
    53     if(low[x]==dfn[x]){
    54         scc_num++;
    55         int tmp;
    56         do{
    57             tmp=sta[tp--];
    58             vis[tmp]=0;
    59             scc[tmp]=scc_num;
    60             ww[scc_num]+=w[tmp];
    61             vv[scc_num]+=v[tmp];
    62         }while(tmp!=x);
    63     }
    64 }
    65 int main(){
    66     n=R(),m=R();
    67     for(int i=1;i<=n;i++) w[i]=R();
    68     for(int i=1;i<=n;i++) v[i]=R();
    69     for(int i=1;i<=n;i++){
    70         d[i]=R();
    71         if(d[i]) addedge(d[i],i);
    72     }
    73     for(int i=1;i<=n;i++){
    74         if(!dfn[i]) tarjan(i);
    75     }
    76     memset(head,0,sizeof head);
    77     memset(ed,0,sizeof ed);ecnt=0;
    78     for(int i=1;i<=n;i++){
    79         int f=d[i],to=i;
    80         if(scc[f]!=scc[to]&&f) addedge(scc[f],scc[to]),rd[scc[to]]++;
    81     }
    82     for(int i=1;i<=scc_num;i++)
    83         if(!rd[i]) addedge(scc_num+1,i);//一定要先缩点再加超级源点,否则环是不会和超级源点连上边的 
    84     dfs(scc_num+1);
    85     printf("%d
    ",f[scc_num+1][m]);
    86     return 0;
    87 }
    朴素
      1 #include<bits/stdc++.h>
      2 #define ll long long
      3 #define RE register
      4 using namespace std;
      5 const int maxn=2200;
      6 inline int R(){
      7     RE char b=getchar();int x=0,t=1;
      8     while(b<'0'||b>'9'){if(b=='-') t=-1;b=getchar();}
      9     while(b>='0'&&b<='9') {x=(x<<3)+(x<<1)+b-'0';b=getchar();}
     10     return x*t;
     11 }
     12 struct Edge{
     13     int nxt,to;
     14 }ed[maxn];
     15 int head[maxn],ecnt;
     16 void addedge(int f,int to){
     17     ed[++ecnt].to=to;
     18     ed[ecnt].nxt=head[f];
     19     head[f]=ecnt;
     20 }
     21 int n,m;
     22 int w[maxn],v[maxn],d[maxn];
     23 int ww[maxn],vv[maxn],rd[maxn];
     24 int siz[maxn];
     25 int f[maxn][maxn];
     26 //void dfs(int x){
     27 //    for(int i=ww[x];i<=m;i++) f[x][i]=vv[x];
     28 ////    f[x][ww[x]]=vv[x];
     29 //    for(int i=head[x];i;i=ed[i].nxt){
     30 //        int v=ed[i].to;
     31 //        dfs(v);
     32 //        for(int j=m-ww[x];j>=0;j--) for(int k=0;k<=j;k++){
     33 //            f[x][j+ww[x]]=max(f[x][j+ww[x]],f[x][j+ww[x]-k]+f[v][k]);
     34 //        }
     35 //    }
     36 //}
     37 int id[maxn],num;
     38 void dfs(int x){
     39     id[++num]=x;//划重点
     40     siz[x]=1;
     41     for(int i=head[x];i;i=ed[i].nxt){
     42         int v=ed[i].to;
     43         dfs(v);
     44         siz[x]+=siz[v];
     45     }
     46 }
     47 int dfn[maxn],low[maxn];
     48 bool vis[maxn];
     49 int sta[maxn],tp;
     50 int scc_num,scc[maxn];
     51 void tarjan(int x){
     52     sta[++tp]=x;
     53     vis[x]=1;
     54     dfn[x]=low[x]=++num;
     55     for(int i=head[x];i;i=ed[i].nxt){
     56         int v=ed[i].to;
     57         if(!dfn[v]){
     58             tarjan(v);
     59             low[x]=min(low[x],low[v]);
     60         }
     61         else if(vis[v]) low[x]=min(low[x],dfn[v]);
     62     }
     63     if(low[x]==dfn[x]){
     64         scc_num++;
     65         int tmp;
     66         do{
     67             tmp=sta[tp--];
     68             vis[tmp]=0;
     69             scc[tmp]=scc_num;
     70             ww[scc_num]+=w[tmp];
     71             vv[scc_num]+=v[tmp];
     72         }while(tmp!=x);
     73     }
     74 }
     75 int main(){
     76     n=R(),m=R();
     77     for(int i=1;i<=n;i++) w[i]=R();
     78     for(int i=1;i<=n;i++) v[i]=R();
     79     for(int i=1;i<=n;i++){
     80         d[i]=R();
     81         if(d[i]) addedge(d[i],i);
     82     }
     83     for(int i=1;i<=n;i++){
     84         if(!dfn[i]) tarjan(i);
     85     }
     86     memset(head,0,sizeof head);
     87     memset(ed,0,sizeof ed);ecnt=0;
     88     for(int i=1;i<=n;i++){
     89         int f=d[i],to=i;
     90         if(scc[f]!=scc[to]&&f) addedge(scc[f],scc[to]),rd[scc[to]]++;
     91     }
     92     for(int i=1;i<=scc_num;i++)
     93         if(!rd[i]) addedge(scc_num+1,i);//一定要先缩点再加超级源点,否则环是不会和超级源点连上边的 
     94     memset(dfn,0,sizeof dfn);num=0;
     95     dfs(scc_num+1);
     96     for(int i=num;i;i--){//划重点
     97         for(int j=0;j<=m;j++)
     98         if(j-ww[id[i]]>=0) f[i][j]=max(f[i+siz[id[i]]][j],f[i+1][j-ww[id[i]]]+vv[id[i]]);//划重点
     99         else f[i][j]=f[i+siz[id[i]]][j];//划重点——————尤其重点
    100     }
    101     printf("%d
    ",f[1][m]);//划重点
    102     return 0;
    103 }
    dfs序

    这道题让我调了一下午的原因竟是……………………Tarjan写错了。。

  • 相关阅读:
    Java框架之SpringMVC
    Java进阶之路
    Java入门基础教学(含配置环境变量等)
    Vue 入门学习
    WCF综合运用之:文件断点续传
    爬取集思录数据(1)--强赎表
    爬虫知识点(一)
    已知1、某股票的增减持日期,2、股票从上市至今的交易数据,求减持后(交易日)1天,5天,15天的收盘价。
    从tushare获取增减持数据
    生成文本序列
  • 原文地址:https://www.cnblogs.com/sdfzjdx/p/11267590.html
Copyright © 2011-2022 走看看