【Luogu】P2015二叉苹果树(DP,DFS)

 

题目链接

设f[i][j][k]表示给以i为根节点的子树分配j条可保留的树枝名额的时候,状态为k时能保留的最多苹果。
k有三种情况。
k=1:我只考虑子树的左叉,不考虑子树的右叉,此时子树能保留的最多的苹果。
k=2:我只考虑子树的右叉,不考虑子树的左叉,此时子树能保留的最多的苹果。
k=3:我既考虑子树的左叉,又考虑子树的右叉,此时子树能保留的最多的苹果。
这样状态转移方程就出来了。
f[i][j][1]=max(f[i][j][1],f[leftson[i]][j-1][3]+val[i][leftson[i]])
f[i][j][2]=max(f[i][j][2],f[rightson[i]][j-1][3]+val[i][rightson[i]])
f[i][j][3]=max(f[i][j][3],f[i][v][1]+f[i][j-v][2]) 其中v从0到j枚举。
最后f[1][q][3]就是最终的答案。
注意记忆化搜索。我因为这个T了四次。

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

struct Edge{
    int next,to,val;
}edge[100010];
int head[100010],num;
int father[100010];
int size[100010];
inline void add(int from,int to,int val){
    edge[++num]=(Edge){head[from],to,val};
    head[from]=num;
}

void find(int x,int fa){
    father[x]=fa;
    size[x]=1;
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(to!=fa){
            find(to,x);
            size[x]+=size[to];
        }
    }
}

int f[103][103][4];

void dfs(int x,int s){
    if(size[x]==1||f[x][s][3])    return;
    int cnt=0;
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(to==father[x])    continue;
        cnt++;
        for(int v=0;v<size[to]&&v<s;++v){
            dfs(to,v);
            f[x][v+1][cnt]=f[to][v][3]+edge[i].val;
        }
    }
    for(int v=0;v<=s;++v)
        f[x][s][3]=max(f[x][s][3],f[x][v][1]+f[x][s-v][2]);
    return;
}

int main(){
    int n=read(),q=read();
    for(int i=1;i<n;++i){
        int from=read(),to=read(),val=read();
        add(from,to,val);
        add(to,from,val);
    }
    find(1,1);
    dfs(1,q);
    printf("%d",f[1][q][3]);
    return 0;
}

 

posted @ 2017-09-22 11:01  Konoset  阅读(318)  评论(1编辑  收藏  举报