• 内网 可怜与超市题解 树形dp+合并


    调过了题比较高兴

    首先想到了dp柿子 f[i][j][0/1]代表第i个节点买了j个用(1)没用(0)优惠券的最小花费。

    而且是从子节点向父节点转移。

    f[i][j][0]=min(f[k][l][0]+f[i][j-l][0]) k是i的儿子,l属于sz[i]。

    f[i][j][1]=min(min(f[k][l][1],f[k][l][0])+f[i][j-l][1]) 同上。

    然后暴力转移,发现是n3复杂度,最多T70(再次%%%有钱人用我的柿子暴力卡过)

    有钱人的暴力方法:判断当前钱数是否超过了所带的钱数,超过根本无法转移。

    其实这个卡常我也想到了但是没有打全因为懒话说打正解不是更麻烦么嘤嘤嘤

    说一下正解

    运用到了学长在写考试T2时的思想,也就是合并,具体证明参见skyh博客%%%%%

    然后我们发现它也可以合并(估计学长就是想让我们练这个)

    tmp数组1维滚动,2维代表用没用优惠券,3维代表买了几个 (两个半维)

    先把自己加上去,sz++,然后tmp赋初值。

    接下来枚举儿子,让当前大小j和儿子大小k共同去更新j+k,在更新完之后去加上儿子的大小

    所以复杂度会从n3下降到n2,最后更新答案。

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define ll long long
     5 using namespace std;
     6 int const maxn=5010;
     7 int const inf=0x3f3f3f3f;
     8 struct node{int to,nxt;}l[5010];
     9 int n,b,tot,head[maxn],c[maxn],d[maxn],fa[maxn],sz[maxn],f[maxn][maxn][2],ans,tmp[2][2][maxn];
    10 void add(int x,int y)
    11 {
    12     l[++tot].to=y;
    13     l[tot].nxt=head[x];
    14     head[x]=tot;
    15 }
    16 void dfs(int x)
    17 {
    18     sz[x]=1;
    19     for(int i=head[x];i;i=l[i].nxt)
    20     {
    21         dfs(l[i].to);
    22         sz[x]+=sz[l[i].to];
    23     }
    24     for(int i=0;i<=sz[x];i++) f[x][i][0]=f[x][i][1]=inf;
    25     if(sz[x]==1)
    26     {
    27         f[x][0][0]=0;f[x][1][0]=c[x];f[x][1][1]=c[x]-d[x];
    28         return ;
    29     }
    30     memset(tmp,0x3f,sizeof(tmp));
    31     int tm=0,size=1,cur=0;
    32     tmp[0][0][0]=0;tmp[0][0][1]=c[x];tmp[0][1][1]=c[x]-d[x];
    33     for(int i=head[x];i;i=l[i].nxt)
    34     {    
    35         int y=l[i].to;tm++;
    36         memset(tmp[cur^1],0x3f,sizeof(tmp[cur^1]));
    37         for(int j=size;j>=0;j--)
    38         {
    39             for(int k=0;k<=sz[y];k++)
    40             {
    41                 tmp[cur^1][0][j+k]=min(tmp[cur^1][0][j+k],min(tmp[cur][0][j]+f[y][k][0],tmp[cur][0][j+k]));
    42                 if(j!=0) tmp[cur^1][1][j+k]=min(tmp[cur^1][1][j+k],min(tmp[cur][1][j]+min(f[y][k][0],f[y][k][1]),tmp[cur][1][j+k]));    
    43             }
    44         }
    45         cur^=1;size+=sz[y];
    46     }
    47     for(int i=1;i<=sz[x];i++) f[x][i][0]=tmp[cur][0][i],f[x][i][1]=tmp[cur][1][i];
    48 }
    49 int main()
    50 {
    51     scanf("%d%d",&n,&b);
    52     scanf("%d%d",&c[1],&d[1]);
    53     memset(f,0x3f,sizeof(f));
    54     for(int i=2;i<=n;i++)
    55     {
    56         scanf("%d%d%d",&c[i],&d[i],&fa[i]);
    57         add(fa[i],i);
    58     }
    59     dfs(1);
    60     for(int i=0;i<=n;i++)
    61     {
    62         if(f[1][i][0]<=b) ans=max(ans,i);
    63         if(f[1][i][1]<=b) ans=max(ans,i);
    64     }
    65     printf("%d",ans);
    66     return 0;
    67 }
    丑陋的代码
  • 相关阅读:
    vue 点击出现下拉菜单,点击下拉菜单以外都要关闭菜单
    关于SET ANSI_PADDING的用法
    VUE中的/deep/用法
    VUE中的/deep/用法
    数字与字符串系列教材 (十)- 自己开发一个Java StringBuffer
    数字与字符串系列教材 (九)- Java StringBuffer常见方法
    数字与字符串系列教材 (八)- Java 比较字符串详解
    数字与字符串系列教材 (七)- Java常见字符串方法
    数字与字符串系列教材 (六)- Java中的字符串String详解
    数字与字符串系列教材 (六)- Java中的字符串String详解
  • 原文地址:https://www.cnblogs.com/MouDing/p/11192653.html
Copyright © 2020-2023  润新知