树形DP

Posted zx1473619689

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树形DP相关的知识,希望对你有一定的参考价值。

一、P2656 采蘑菇

技术图片
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
#define maxn 80010
#define maxm 300010
struct Edge{
    int u,v,w,next;
    double k;
}edge[maxm];

int head[maxn],instack[maxn],stack[maxn],Belong[maxn];
int DFN[maxn],LOW[maxn],n,m,ant,Index,top,Bcnt;
int point[maxn],S,ans[maxn];

void adde(int u,int v,int w,double k){
    edge[ant].u=u,edge[ant].v=v;
    edge[ant].w=w,edge[ant].k=k;
    edge[ant].next=head[u],head[u]=ant++;
}

void tarjan(int u){
    DFN[u]=LOW[u]=++Index;
    instack[u]=true;
    stack[++top]=u;
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(!DFN[v]){
            tarjan(v);
            if(LOW[v]<LOW[u])    LOW[u]=LOW[v];
        }
        else{
            if(instack[v]&&DFN[v]<LOW[u])    LOW[u]=DFN[v];
        }
    }
    if(DFN[u]==LOW[u]){
        Bcnt++;
        int j;
        do{
            j=stack[top--];
            instack[j]=false;
            Belong[j]=Bcnt;
        }
        while(j!=u);
    }
}

void solve(){
    top=Bcnt=Index=0;
    for(int i=1;i<=n;i++){
        if(!DFN[i])
            tarjan(i);
    }
}

void dfs(int p){
    ans[p]+=point[p];
    int t=0;
    for(int i=head[p];i!=-1;i=edge[i].next){
        int v=edge[i].v,w=edge[i].w;
        if(!ans[v])    dfs(v);
        t=max(t,ans[v]+w);    
    }
    ans[p]+=t;
}

int main(){
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int u,v,w;
        double k;
        scanf("%d%d%d%lf",&u,&v,&w,&k);
        adde(u,v,w,k);
    }
    scanf("%d",&S);
    solve();
    memset(head,-1,sizeof(head));
    for(int i=0;i<m;i++){
        int u=edge[i].u,v=edge[i].v;
        int w=edge[i].w;
        double k=edge[i].k;
        if(Belong[u]!=Belong[v]){
            
            adde(Belong[u],Belong[v],w,k);
        }else{
            while(w){
                point[Belong[u]]+=w;
                w=floor(w*k);
            }
        }
    }
    dfs(Belong[S]);
    printf("%d
",ans[Belong[S]]);
    return 0;
}
View Code

缩点模板题,dfs一开始还写错了。

 

二、P1040 加分二叉树

技术图片
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
#define maxn 35

long long w[maxn],n,dp[maxn][maxn],root[maxn][maxn];

void myprint(int l,int r){
    if(l>r)    return;
    printf("%d ",root[l][r]);
    myprint(l,root[l][r]-1);
    myprint(root[l][r]+1,r);
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)    scanf("%lld",&w[i]);
    for(int i=0;i<=n;i++){
        dp[i+1][i]=1;
        root[i][i]=i;
        dp[i][i]=w[i];
    }    
    for(int len=2;len<=n;len++){
        for(int i=1;i<n;i++){
            int j=i+len-1;
            for(int k=i;k<=j;k++){
                if(dp[i][j]<dp[i][k-1]*dp[k+1][j]+w[k]){
                    dp[i][j]=dp[i][k-1]*dp[k+1][j]+w[k];
                    root[i][j]=k;
                }
            }
        }
    }
    printf("%lld
",dp[1][n]);
    myprint(1,n);
    return 0;
}
View Code

如果现在给出一个中序遍历的序列,并且给出你所有子树根节点 ,123456789(8是整个树的根,4是子树[1,6]的根(用区间表示子树),2是树[1,6]的子树[1,3]的根,而5是树[1,6]的子树[5,6]的根)。

root数组看的题解,有点妙!

以上是关于树形DP的主要内容,如果未能解决你的问题,请参考以下文章

Starship Troopers(HDU 1011 树形DP)

HDU1520 Anniversary party(树形dp入门题)

[填坑][支线任务]树形DP 树形背包

hdu1561 树形dp+背包

BZOJ_1060_时态同步_树形DP

HDU 1520 Anniversary party (树形DP)