Acwing 286.选课 (树上依赖背包)

题目

学校实行学分制。

每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分。

学校开设了 N 门的选修课程,每个学生可选课程的数量 M 是给定的。

学生选修了这 M 门课并考核通过就能获得相应的学分。

在选修课程中,有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其他的一些课程的基础上才能选修。

例如《Windows程序设计》必须在选修了《Windows操作基础》之后才能选修。

我们称《Windows操作基础》是《Windows程序设计》的先修课。

每门课的直接先修课最多只有一门。

两门课可能存在相同的先修课。

你的任务是为自己确定一个选课方案,使得你能得到的学分最多,并且必须满足先修条件。

假定课程之间不存在时间上的冲突。

输入格式
输入文件的第一行包括两个整数N、M(中间用一个空格隔开)其中1≤N≤300,1≤M≤N。

接下来N行每行代表一门课,课号依次为1,2,…,N。

每行有两个数(用一个空格隔开),第一个数为这门课先修课的课号(若不存在先修课则该项为0),第二个数为这门课的学分。

学分是不超过10的正整数。

输出格式
输出一个整数,表示学分总数。

输入样例:
7 4
2 2
0 1
0 4
2 1
7 1
7 6
2 2
输出样例:
13

思路

这个问题和那道上司的舞会很像,但又很不一样。其一,这个问题里面,我们不只有一棵树,所有的依赖关系可能是由森林的形式给出,其二,这些课之间的依赖关系如何处理。那么对于第一个问题来说,我们可以利用一个图论里面常用的思路,建一个超级源点,然后只需要求0点的dp值就好了。对于第二个点的话,我们可以把一个点下悬挂的n棵子树看做是n组的背包,每组背包里面的物品体积是1到m-1,然后我们做一次分组背包,但是要注意做背包的时候要在总体积上减去1,保留父亲的位置,以保障依赖关系。

代码实现

#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
#define rep(i,f_start,f_end) for (int i=f_start;i<=f_end;++i)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define MT(x,i) memset(x,i,sizeof(x) )
#define rev(i,start,end) for (int i=0;i<end;i++)
#define inf 0x3f3f3f3f
#define mp(x,y) make_pair(x,y)
#define lowbit(x) (x&-x)
#define MOD 1000000007
#define exp 1e-8
#define N 1000005 
#define fi first 
#define se second
#define pb push_back
typedef long long ll;
typedef pair<int ,int> PII;
typedef pair<int ,PII> PIII;
ll gcd (ll a,ll b) {return b?gcd (b,a%b):a; }
inline int read() {
    char ch=getchar(); int x=0, f=1;
    while(ch<'0'||ch>'9') {
        if(ch=='-') f = -1;
        ch=getchar();
    } 
    while('0'<=ch&&ch<='9') {
        x=x*10+ch-'0';
        ch=getchar();
    }   return x*f;
}

const int maxn=310;
int  n,m;
vector <int > v[maxn];
int w[maxn];
int f[maxn][maxn];   //f[root][m]

void dfs (int u) {
    rev (i,0,v[u].size ()) {
        int son=v[u][i];
        dfs (son);
        
        per (j,m-1,0) {
            rep (k,1,j) {
                f[u][j]=max (f[u][j],f[u][j-k]+f[son][k]);
            }
        }
    }
    per (i,m,1) {
        f[u][i]=f[u][i-1]+w[u];
    }
    f[u][0]=0;
}

int main () {
    cin>>n>>m;
    rep (i,1,n) {
       int a;
       cin>>a>>w[i];
       v[a].pb (i);
    }
    m++;
    dfs (0);

    cout<<f[0][m]<<endl;

    return 0;
}
posted @ 2020-08-06 11:42  Luglucky  阅读(129)  评论(0编辑  收藏  举报