题意:
现在有 N门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程a是课程b的先修课即只有学完了课程a,才能学习课程b)。
一个学生要从这些课程里选择 M 门课程学习,问他能获得的最大学分是多少
思路:
样例:
7 4 2 2 0 1 0 4 2 1 7 1 7 6 2 2
答案
13
第二行开始v,w,第i+1行v和i连接,i点点值是w,如果是v==0,就是不需要任何直接先修课
所以将他们看出以0的根的树,进行从底往高的处理dp,dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]);
初始值是dp[i][1]=w[i],因为虚构了一个0的科目,所以选课数量+1,就当作0这么科目必须修,但他的学分是0
#include<bits/stdc++.h> using namespace std; #define ll long long #define il inline #define it register int #define inf 0x3f3f3f3f #define lowbit(x) (x)&(-x) #define mem(a,b) memset(a,b,sizeof(a)) #define mod 1000000007 const int maxn=310; struct node{ int to,next; }a[maxn<<1]; int n,s,K,cnt,tot,head[maxn],w[maxn]; int dp[maxn][maxn],sz[maxn]; il void add(int u,int v){ a[tot].next=head[u]; a[tot].to=v;head[u]=tot++; } void dfs(int u,int fa){ dp[u][1]=w[u];sz[u]=1; for(it i=head[u];i!=-1;i=a[i].next){ it v=a[i].to;if(v==fa){continue;} dfs(v,u); sz[u]+=sz[v]; } for(it i=head[u];i!=-1;i=a[i].next){ it v=a[i].to;if(v==fa){continue;} for(it j=K;j>=1;j--){ for(it k=1;k<min(j,sz[u]);k++){ dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]); } } } } int main(){ mem(head,-1);tot=0; scanf("%d%d",&n,&K);K++;w[0]=0; for(it i=1;i<=n;i++){ int v; scanf("%d%d",&v,&w[i]); add(i,v);add(v,i); } dfs(0,-1); printf("%d ",dp[0][K]); return 0; }
这题一开始没想到以0为根的树,所以我把所有的树进行了分开算,代码量是真的大,然后写得一塌糊涂,然后看了一眼题解,然后就重写了就过了