洛谷P2014 选课

题意:

现在有 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\n",dp[0][K]);
    return 0;
}

 

 

 

这题一开始没想到以0为根的树,所以我把所有的树进行了分开算,代码量是真的大,然后写得一塌糊涂,然后看了一眼题解,然后就重写了就过了

posted @ 2020-02-08 22:40  ouluy  阅读(112)  评论(0编辑  收藏  举报