DP训练 Codeforces 816E Karen And SuperMarket [树形DP]

来源:互联网 发布:怎么盗用淘宝视频 编辑:程序博客网 时间:2024/05/22 00:37

找到原题。

购物 (shopping.cpp/c/pas)

【题目描述】
商店里有n个物品,第i个物品的价格为ci元。每个物品只能买一次。商店发行了n张优惠券,每个物品各有一张优惠卷。如果使用了第i张优惠券,可以使该物品便宜di元钱,必须买商品才能够使用相对应的优惠券。第1张优惠卷可以无条件使用,但对于第i>=2张优惠卷,如果需要使用第i张优惠券,则必须先使用xi这张优惠券。
现在有b元钱,问最多能购买多少商品。
【输入格式】
第一行两个整数n,b。
接下来n行,第i行先有两个整数ci,di,如果i >= 2,紧接着有第三个整数xi。
【输出格式】
一行,一个整数表示最多购买的商品数量。
【样例输入】
8 9
4 3
8 3 1
2 1 1
4 2 2
7 2 2
3 1 2
7 3 5
2 1 3
【样例输出】
4
【数据范围】
对于30%的数据,n <= 100。
对于100%的数据,1 <= n <= 5000,1 <= b <= 10^9,1 <= di < ci <= 10^9,对于i >= 2有1 <= xi < i。

思考

既然是原题,我就不写题解了,讲一讲复杂度就行了。
学过树链剖分启发式合并的同学很清楚那个复杂度是O(nlogn)的,那么对于这道题来说,不管你是重儿子还是轻儿子,都会被暴力计算,每个点都会被其他点for一遍?(存疑),所以最坏时间复杂度为(3n22+n),是O(n2)级别的,所以不存在TLE的。

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int N=5005;struct Edge{    int to,nxt;}E[N<<1];int head[N],tot,cnt;int n,b,ans;struct data{    int c,d;}Tr[N];template<class T>inline void read(T &res){    static char ch;T flag=1;    while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1;res=ch-48;    while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-48;res*=flag;}void addedge(int u,int v){    E[++tot].to=v,E[tot].nxt=head[u],head[u]=tot;}void minn(int &x,int y){x=min(x,y);}int dp[N][N][2],size[N];void dfs(int u){    size[u]=1,dp[u][0][0]=0,dp[u][1][0]=Tr[u].c,dp[u][1][1]=Tr[u].c-Tr[u].d;    for(register int v,i=head[u];i;i=E[i].nxt){        v=E[i].to;dfs(v);        for(register int j=size[u];j>=0;j--)            for(register int k=0;k<=size[v];k++)                cnt++,minn(dp[u][j+k][0],dp[u][j][0]+dp[v][k][0]),                minn(dp[u][j+k][1],dp[u][j][1]+dp[v][k][0]),                minn(dp[u][j+k][1],dp[u][j][1]+dp[v][k][1]);        size[u]+=size[v];    }}int main(){//  freopen("shopping.in","r",stdin);//  freopen("shopping.out","w",stdout);    memset(dp,0x3f,sizeof(dp));    read(n),read(b);    read(Tr[1].c),read(Tr[1].d);    for(register int u,i=2;i<=n;i++)        read(Tr[i].c),read(Tr[i].d),read(u),addedge(u,i);       dfs(1);    for(register int i=n;i>=0;i--)        if(dp[1][i][0]<=b||dp[1][i][1]<=b){ans=i;break;}    cout<<ans<<endl;    cout<<cnt<<endl;    return 0;}/*17 94 38 3 12 1 14 2 37 2 33 1 57 3 57 3 77 3 73 1 97 3 97 3 117 3 113 1 137 3 137 3 157 3 1515 94 38 3 12 1 14 2 27 2 23 1 37 3 37 3 47 3 47 3 57 3 57 3 67 3 67 3 77 3 7*/
阅读全文
0 0