DP訓練 Codeforces 816E Karen And SuperMarket [樹形DP]

找到原題。

購物 (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 9
4 3
8 3 1
2 1 1
4 2 3
7 2 3
3 1 5
7 3 5
7 3 7
7 3 7
3 1 9
7 3 9
7 3 11
7 3 11
3 1 13
7 3 13
7 3 15
7 3 15

15 9
4 3
8 3 1
2 1 1
4 2 2
7 2 2
3 1 3
7 3 3
7 3 4
7 3 4
7 3 5
7 3 5
7 3 6
7 3 6
7 3 7
7 3 7
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章