• P1270 【“访问”美术馆】


    $large{ ext{一千个Oier程序中有一千种树形DP}}$

    思路都差不多的,但是每个人都有自己的状态定义与转移

    不妨定义$dp[i][j]$表示,在$i$子树内,偷$j$张画,且不考虑根到$i$父节点路径代价的最短时间

    $a[i]$表示$i$与其父节点的距离

    $d[i]$表示$i$到根节点的距离

    不难想出转移

    $large{dp[i][j]=minleft{dp[son1][k]+dp[son2][j-k]+dis[x] ight}}$

    统计答案

    枚举每个节点选几个,如果$dp[i][j]+d[i]-a[i]<=s$,更新答案

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int size[1010],s,cnt,a[1010],v[1010],e[1010][2],dp[1010][2010],ans,d[1010];
    void init(int x)
    {
        int t,to;
        if(scanf("%d%d",&t,&to)!=2)
            return;
        d[x]+=2*t,a[x]=2*t,dp[x][0]=0;
        if(to)
            v[x]=to;
        else
        {
            d[++cnt]=d[x],init(e[x][0]=cnt);
            d[++cnt]=d[x],init(e[x][1]=cnt);
        }
    }
    void dfs(int x)
    {
        if(!x)
            return;
        dfs(e[x][0]),dfs(e[x][1]);
        size[x]=v[x]+size[e[x][0]]+size[e[x][1]];
        if(v[x])
            for(int i=1;i<=v[x];i++)
                dp[x][i]=a[x]+dp[x][0]+5*i;
        else
            for(int i=1;i<=size[x];i++)
                for(int j=0;j<=i;j++)
                    dp[x][i]=min(dp[x][i],dp[e[x][0]][j]+dp[e[x][1]][i-j]+a[x]);
    }
    int main()
    {
        scanf("%d",&s);
        memset(dp,0x3f,sizeof(dp));
        init(++cnt);
        dfs(1);
        for(int i=1;i<=cnt;i++)
            for(int j=1;j<=size[i];j++)
                if(dp[i][j]+d[i]-a[i]<s)
                    ans=max(ans,j);
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    [tip]build x86+x64 parrelly for your VS solution
    float double的内存表示及比较大小的方法
    [Problem 13]欧拉
    Interface Project
    [复习]内存对齐
    [tip]VS online Gallery in Extention Manager
    [Problem 14]欧拉
    “火柴棍式”程序员面试题打破惯性思维
    [复习]时间复杂度及计算
    ModuleCatalog配置文件
  • 原文地址:https://www.cnblogs.com/ivanovcraft/p/9776928.html
Copyright © 2020-2023  润新知