选课

选课

有n门课程,第i门课程的学分为\(a_i\),每门课程最多有一个先修课程,表示只有选了这一门课程才能选另一门课程,现在要从中选出m个课程,求最大的学分之和,\(1≤N≤300\)

有依赖的问题经常是树形递推,肯定要表现选到哪一个节点,自然也要表现选了几门课,于是设\(f[x][y]\)表示以第x门课程为根节点的子树中选了y门课程的学分之和,\(x_i\)为节点x的第x个儿子。

然后又注意到问题是森林,于是可以把每一棵树的根节点并到同一个根节点0,组成一棵树,因此不难有

\[f[x][y]=\max_{\sum_{i=1}^{|son(x)|}k_i=y-1}(\sum_{i=1}^{|son(x)|}f[x_i][y_i])+a_x \]

注意到其实是确定了选多少门课,再从每一棵子树中选出一些课,让选的课数纸盒正好为y-1,类似与分组背包,于是转移方程可以转换为,对于其子树\(x_i\)而言

\[f[x][y]=\max_{j=0}^{\min(y-1,m)}(f[x][y-j]+f[x_i][j]) \]

边界:\(f[x][0]=0,f[x][1]=a_x,i=0,1,2,...,n\),其余负无限大

参考代码:

dfs

#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
using namespace std;
struct point{
    point*next;int to;
}*pt,*head[301];
int n,m,in[301],dp[301][302];
il void read(int&),link(int,int);
void dfs(int);il int max(int,int);
int main(){
    read(n),read(m),memset(dp,-10,sizeof(dp));
    for(int i(1),j;i<=n;++i){
        read(j),read(dp[i][1]);
        if(j)link(j,i),++in[i];
    }++m;
    for(int i(1);i<=n;++i)if(!in[i])link(0,i);
    dfs(0),printf("%d",dp[0][m]);
    return 0;
}
il int max(int a,int b){
    return a>b?a:b;
}
void dfs(int x){
    dp[x][0]=0;
    for(point *i(head[x]);i!=NULL;i=i->next){
        dfs(i->to);
        for(int j(m),k;j;--j)
            for(k=j-1;k;--k)
                dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[i->to][k]);
    }
}
il void link(int u,int v){
    pt=new point,pt->to=v;
    pt->next=head[u],head[u]=pt;
}
il void read(int &x){
    x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}

bfs

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#define il inline
#define ri register
using namespace std;
queue<int>T;
int in[301],pa[301],n,m,
    dp[301][302];
il void read(int&);
il int dag(),max(int,int);
int main(){
    read(n),read(m),memset(dp,-10,sizeof(dp));
    for(int i(1),j;i<=n;++i)
        read(j),read(dp[i][1]),
            ++in[j],pa[i]=j,dp[i][0]=0;
    ++pa[0],++m,printf("%d",dag());
    return 0;
}
il int max(int a,int b){
    return a>b?a:b;
}
il int dag(){
    dp[0][0]=dp[0][1]=0;
    for(int i(1);i<=n;++i)if(!in[i])T.push(i);
    while(!T.empty()){
        int s(T.front());T.pop();
        for(int i(m);i;--i)
            for(int j(i-1);j;--j)
                dp[pa[s]][i]=max(dp[pa[s]][i],dp[pa[s]][i-j]+dp[s][j]);
        --in[pa[s]];if(!in[pa[s]])T.push(pa[s]);
    }return dp[0][m];
}
il void read(int &x){
    x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}

posted @ 2019-05-26 20:32  a1b3c7d9  阅读(149)  评论(0编辑  收藏  举报