P2014 選課 題解(樹形DP)
阿新 • • 發佈:2018-12-18
show dfs for 建圖 sca () 包括 ems 遍歷 個節點的子樹。
題目鏈接
P2014 選課
解題思路
樹形動歸,用\(f[i][j]\)表示以\(i\)為根,\(j\)個子節點(不包括自己)的最大學分
首先根據題意建圖,用根節點\(0\)將森林連成樹。
從根節點開始\(DFS\)遍歷,遍歷到葉節點後回溯,回溯過程中將\(f[i][j]\)更新,利用背包的思想。
\(DFS\)過程中,\(num\)為離根節點0更近的定點,遍歷的\(i\)為\(num\)的子節點,容易得出遞推關系式:
\(f[num][j]=max\{f[num][j],f[num][j-k-1]+f[i][k]\}\)。這裏的\(j-k-1\)表示以\(num\)為頂點(因為\(num\)可以有多個子樹),擁有\(k-1\)
AC代碼
#include<stdio.h> #include<string.h> int max(int a,int b){return a>b?a:b;} int f[310][310],next[310],head[310],s; int dfs(int num){ if(head[num]==-1)return 0;//葉節點 int i,j,k,sum=0,t; for(i=head[num];i!=-1;i=next[i]){//遍歷該節點所連邊 t=dfs(i);//以i為根的子樹節點數 sum+=t+1;//總和+i for(j=sum;j>=0;j--)//節點個數 for(k=0;k<=t&&k<=j-1;k++)//以i為根的子樹f[i][k]+i+以num為根的子樹f[num][j-1-k] f[num][j]=max(f[num][j],f[num][j-1-k]+f[i][k]); } return sum; } int main(){ int i,n,m,a; scanf("%d%d",&n,&m); memset(head,-1,sizeof(head)); for(i=1;i<=n;i++){ scanf("%d%d",&a,&s); f[i][0]=s;//根節點的學分最大值初始為本身 next[i]=head[a];//前向星建有向圖 head[a]=i; } dfs(0);//0為根 printf("%d",f[0][m]);//以0為根的子樹學分最大值 return 0; }
P2014 選課 題解(樹形DP)