[机房测试]购物

Description

\(n\) 个物品,价值为 \(a_i\),使用优惠券会便宜 \(d_i\),优惠券使用限制构成树形关系,必须父亲使用了优惠券,当前点才能使用。现有 \(b\leq 10^9\) 元钱,求最多能买多少个物品。

Solution

MLE了,唱歌。

不能将费用计入状态,所以可以考虑反过来将个数计入状态。\(dp_{u,j,0/1}\) 表示以 \(u\) 为根的子树中,选了 \(j\) 个数,\(u\) 使不使用优惠券的最小花费。那么显然有转移

\[dp_{u,0,0}=0\\ dp_{u,1,0}=a_u\\ dp_{u,1,1}=a_u-d_u\\ dp_{u,j+k,0}=\min\{dp_{u,j,0}+dp_{v,k,0}|j\in [0,sz_u]\}\\ dp_{u,j+k,1}=\min\{dp_{u,j,1}+\min\{dp_{v,k,0},dp_{v,k,1}\}|j\in [1,sz_u]\} \]

#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;

inline int read(){
    int x=0,flag=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return flag? x:-x;
}

const int N=5e3+7;

int sz[N],c[N],d[N];
vector<int> G[N];
int dp[N][N][2]; 

inline void Min(int &x,int y){x=min(x,y);}

void dfs(int u){
    sz[u]=1;
    dp[u][0][0]=0;
    dp[u][1][0]=c[u];
    dp[u][1][1]=c[u]-d[u];
    for(int v:G[u]){
        dfs(v);
        for(int j=sz[u];~j;j--)
            for(int k=sz[v];k;k--){
                if(j) Min(dp[u][j+k][1],dp[u][j][1]+min(dp[v][k][0],dp[v][k][1]));
                Min(dp[u][j+k][0],dp[u][j][0]+dp[v][k][0]);
            }
        sz[u]+=sz[v];
    }
}

int main(){
    freopen("shopping.in","r",stdin);
    freopen("shopping.out","w",stdout);
    int n=read(),b=read();
    for(int i=1;i<=n;i++){
        c[i]=read(),d[i]=read();
        if(i>=2) G[read()].push_back(i);
    }
    for(int i=0;i<=n;i++)
        for(int j=0;j<=n;j++)
            dp[i][j][0]=dp[i][j][1]=b+1;
    dfs(1);
    for(int i=n;~i;i--)
        if(min(dp[1][i][0],dp[1][i][1])<=b) return printf("%d",i),(0-0);
}
原文地址:https://www.cnblogs.com/wwlwQWQ/p/15419806.html