[luogu] P2014 [CTSC1997]选课

题目详情
题目分析:

  • f[i][j]表示以i为根节点,选j个节点,获得的最大分数
  • dfs(u)的作用就是算出以u为节点时,分别选0~m个节点各自的最大值
  • 解释为什么k从j - 1开始,u是v的父节点,选v必须先选u这节先修课。假设如果k能取到j,有
    f [ u ] [ j ] = m a x ( f [ u ] [ j ] , f [ u ] [ 0 ] + f [ v ] [ j ] ) ; f[u][j] = max(f[u][j], f[u][0] + f[v][j]); f[u][j]=max(f[u][j],f[u][0]+f[v][j]);
    由上式我们知道不可能以v为节点选了j个,而它的父节点只选了零个,这是不可能的。所以k < j.
  • 解释
    f [ u ] [ j − k ] + f [ v ] [ k ] f[u][j - k] + f[v][k] f[u][jk]+f[v][k]
    u有很多子节点,v只是其中一个,当以v为根节点时选k节课时,剩下的同父子节点只能选j - k个。
  • 解释m要倒序遍历,因为f[u][j - k]转移到f[u][j],更新f[u][j]时,保证f[u][j - k]没有被更新过,所以倒序。
#include <cstdio>
#include <algorithm>
using namespace std;
int n, m, score[333], a, f[333][333], head[333], cnt;
struct edge{
    int to, next;
} e[333];
void add(int u, int v){
    e[++cnt] = edge{v, head[u]};//c++11标准的写法
    head[u] = cnt;
}
void dfs(int u){
    f[u][1] = score[u];
    for (int i = head[u]; i; i = e[i].next){
        int v = e[i].to;
        dfs(v);
        for (int j = m; j > 0; j--)
            for (int k = j - 1; k > 0; k--)
                f[u][j] = max(f[u][j], f[u][j - k] + f[v][k]);
    }
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++){
        scanf("%d%d", &a, score + i);
        add(a, i);
    }
    m++;//0节点也选了,一共m + 1 个节点,所以m++;
    dfs(0);//从零节点开始搜索。
    printf("%d\n", f[0][m]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值