首页 > 其他 > 详细

CF815C Karen and Supermarket

时间:2019-10-26 17:55:42      阅读:84      评论:0      收藏:0      [点我收藏+]

CF815C Karen and Supermarket

树上DP。
首先,考虑建边。显然连一条\(x[i]->i\)的边。
其次,考虑DP。那么有数组\(f[i][j][k]\)表示\(i\)为根节点的子树中,选择\(j\)件物品的代价;\(k\)代表是否使用折扣
最后看输出。那就看以\(1\)为根节点,选择\(ans\)件物品,无论打不打折,如果代价小于\(b\),则可行。此外,为了使\(ans\)尽量大,所以我们要从\(n\)\(1\)遍历寻找答案。

#include<bits/stdc++.h>
#define N 5010

using namespace std;

int n,b,cnt,ans;
int c[N],d[N],x[N],head[N],siz[N],f[N][N][2]; //f[i][j][k] 以i为根节点的子树中,选择j件物品的代价;k代表是否使用折扣

struct node {
    int nxt,to;
}edge[N];

void addEdge(int u,int v) {
    edge[++cnt]=(node){head[u],v};
    head[u]=cnt;
    return;
}

void Read() {
    scanf("%d%d%d%d",&n,&b,&c[1],&d[1]);
    for(int i=2;i<=n;i++) {
        scanf("%d%d%d",&c[i],&d[i],&x[i]);
        addEdge(x[i],i);
    }
    return;
}

void Init() {
    memset(f,0x3f,sizeof(f));
    return;
}

void DP(int x) {
    siz[x]=1;
    f[x][0][0]=0;
    f[x][1][0]=c[x];
    f[x][1][1]=c[x]-d[x];
    for(int i=head[x];i;i=edge[i].nxt) {
        int v=edge[i].to;
        DP(v);
        for(int i=siz[x];i>=0;i--) {
            for(int j=0;j<=siz[v];j++) {
                //状态转移方程
                f[x][i+j][0]=min(f[x][i+j][0],f[x][i][0]+f[v][j][0]);
                f[x][i+j][1]=min(f[x][i+j][1],f[x][i][1]+f[v][j][0]);
                f[x][i+j][1]=min(f[x][i+j][1],f[x][i][1]+f[v][j][1]);
            }
        }
        siz[x]+=siz[v];
    }
    return;
}

void Print() {
    for(int i=n;i>=1;i--) {
        if(f[1][i][0]<=b||f[1][i][1]<=b) {
            ans=i;
            break;
        }
    }
    printf("%d",ans);
    return;
}

int main()
{
    Read();
    Init();
    DP(1);
    Print();
    return 0;
}

CF815C Karen and Supermarket

原文:https://www.cnblogs.com/luoshui-tianyi/p/11743960.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!