树形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; }
缩点模板题,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; }
如果现在给出一个中序遍历的序列,并且给出你所有子树根节点 ,123456789(8是整个树的根,4是子树[1,6]的根(用区间表示子树),2是树[1,6]的子树[1,3]的根,而5是树[1,6]的子树[5,6]的根)。
root数组看的题解,有点妙!
以上是关于树形DP的主要内容,如果未能解决你的问题,请参考以下文章
Starship Troopers(HDU 1011 树形DP)