• bzoj 1017 : [JSOI2008]魔兽地图DotR


    比较难想的的一道树形dp。

    看到这道题正常的思路应该是$f[i][j][k]$表示i这棵子树里买了j个i物品花费为k的最大收益。

    但如果直接这么定义的话转移复杂度会很高,需要枚举j,枚举孩子,枚举k,枚举孩子的花费,还要枚举每个孩子各买了多少件。

    想办法把最后一个循环去掉。

    重新定义状态$f[i][j][k]$表示表示i这棵子树里至少买了j个i物品花费为k的最大收益。

    每次枚举完物品数量后加上这么一句

    if(i!=l[x])f[x][i][j]=max(f[x][i][j],f[x][i+1][j]);

    l[x]为x的最大数量。

    相当于一个后缀最大值。

    就可以轻松转移了。

    虽然复杂度还是有些高。(貌似存在复杂度更低的算法?)

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #define inf 0x3f3f3f3f
     6 using namespace std;
     7 int n,m;
     8 int f[55][110][2005];
     9 int g[55][2005];
    10 int v[55],cost[55],l[55];
    11 int head[55],ver[110],nxt[110],tot,quan[110];
    12 void add(int a,int b,int c)
    13 {
    14     tot++;nxt[tot]=head[a];head[a]=tot;ver[tot]=b;quan[tot]=c;return ;
    15 }
    16 bool vis[55];
    17 void dfs(int x)
    18 {
    19     if(!head[x])
    20     {
    21         l[x]=min(l[x],m/cost[x]);
    22         for(int i=0;i<=l[x];i++)
    23         {
    24             for(int j=0;j<=i;j++)
    25             {
    26                 f[x][j][i*cost[x]]=i*v[x];
    27             }
    28         }
    29         return ;
    30     }
    31     l[x]=inf;
    32     for(int i=head[x];i;i=nxt[i])
    33     {
    34         dfs(ver[i]);
    35         l[x]=min(l[x],l[ver[i]]/quan[i]);
    36         cost[x]+=cost[ver[i]]*quan[i];
    37     }
    38     l[x]=min(l[x],m/cost[x]);
    39     memset(g,0xcf,sizeof(g));
    40     g[0][0]=0;
    41     for(int i=l[x];i>=0;i--)
    42     {
    43         int cnt=0;
    44         for(int j=head[x];j;j=nxt[j])
    45         {
    46             cnt++;
    47             for(int k=0;k<=m;k++)
    48             {
    49                 for(int l=0;l<=k;l++)
    50                 {
    51                     g[cnt][k]=max(g[cnt][k],g[cnt-1][l]+f[ver[j]][i*quan[j]][k-l]-v[ver[j]]*(i*quan[j]));
    52                 }
    53             }
    54         }
    55         for(int j=0;j<=m;j++)
    56         {
    57             f[x][i][j]=g[cnt][j]+i*v[x];
    58             if(i!=l[x])f[x][i][j]=max(f[x][i][j],f[x][i+1][j]);
    59         }
    60     }
    61 
    62     return ;
    63 }
    64 int main()
    65 {
    66     scanf("%d%d",&n,&m);
    67     memset(f,0xcf,sizeof(f));
    68     for(int i=1;i<=n;i++)
    69     {
    70         scanf("%d",&v[i]);
    71         char s[2];scanf("%s",s);
    72         if(s[0]=='A')
    73         {
    74             int num;
    75             int t1,t2;
    76             scanf("%d",&num);
    77             for(int j=1;j<=num;j++)
    78             {
    79                 scanf("%d%d",&t1,&t2);
    80                 vis[t1]=1;
    81                 add(i,t1,t2);
    82             }
    83         }
    84         else
    85         {
    86             scanf("%d%d",&cost[i],&l[i]);
    87         }
    88     }
    89     int root=0;
    90     for(int i=1;i<=n;i++)
    91     {
    92         if(!vis[i])add(0,i,1);
    93     }
    94     dfs(root);
    95     int ans=0;
    96     for(int i=0;i<=m;i++)ans=max(ans,f[root][0][i]);
    97     printf("%d
    ",ans);
    98     return 0;
    99 }
  • 相关阅读:
    asp.net 框架接触(2)
    解决:C++ 中 main函数 wmain函数 _tmain函数 WinMain函数 wWInMain函数 _tWinMain函数的区别
    实现:创建/复制/移动文件API
    实现:类模板的数组类封装
    python3 解析shodan_json数据
    实现:API实现创建用户并且添加至管理员
    学习:类模板
    网展cms后台任意文件删除和sql注入
    选择排序
    实现:函数模板实现不同数据类型数组进行排序
  • 原文地址:https://www.cnblogs.com/ezyzy/p/6592745.html
Copyright © 2020-2023  润新知