zoukankan      html  css  js  c++  java
  • 内网 可怜与超市题解 树形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 }
    丑陋的代码
  • 相关阅读:
    android openGL ES2 一切从绘制纹理開始
    HTML5 界面元素 Canvas 參考手冊
    python进阶十_正則表達式(一)
    HDU 3016 Man Down(线段树)
    android 自己定义dialog并实现失去焦点(背景透明)的功能
    上海传智程序员携手设计狮美女雨中烧烤!!
    vim visual操作备忘
    MySQl Study学习之--MySQl二进制日志管理
    Android View measure (三) 经常用法
    Analyze提示:Value stored to &quot;***&quot;is never read
  • 原文地址:https://www.cnblogs.com/MouDing/p/11192653.html
Copyright © 2011-2022 走看看