我是靠谱客的博主 甜甜海燕,最近开发中收集的这篇文章主要介绍【jzoj3418】【NOIP动态规划专题】【选课】【树型依赖动态规划】,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

description

大学里实行学分。每门课程都有一定的学分,学生只要选修了这门课,并通过考核就能获得相应的学分。学生最后的学分是他各门课学分的总和。每个学生都要选择规定数量的课程。其中有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其他的一些课程的基础上才能选修。

例如,《剥皮术》就必须在选修了《屠龙术》后才能选修。

我们称《屠龙术》是《剥皮术》的先修课。

每门课的直接先修课最多之有一门。两门课也可能存在相同的先修课。

每门课都有一个课号,课号依次是1,2,3……。以下表为例说明。

课号 先修课号 学分

1 无 1

2 1 1

3 2 3

4 无 3

5 2 4

上表中1是2的先修课,即如果要选修2,则1必须已被选过。

同样,要选修3,那么1和2都一定被选修过。

每个学生可选的课程总数是一定的,请找出一种方案,使得到的总学分最多。

solution

考虑动态规划,按dfs顺序dp,设f[i][j]表示到dfs序为i的点,选了j个点,当前点可选可不选的最大贡献,每次可以转移到dfs序+1的点,也可以转移到dfs序+size的点,记录一下当前状态由哪个状态转移过来即可。

code

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LF double
#define LL long long
#define ULL unsigned int
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define fr(i,j) for(int i=begin[j];i;i=next[i])
using namespace std;
int const mn=1000+9,inf=1e9+7;
int n,m,w[mn],a[mn],b[mn],size[mn],gra,begin[mn],to[mn],next[mn],f[mn][mn],
    g[mn][mn],h[mn][mn];
void insert(int u,int v){
    to[++gra]=v;
    next[gra]=begin[u];
    begin[u]=gra;
}
void dfs(int p){
    b[++b[0]]=p;
    size[p]=1;
    fr(i,p){
        dfs(to[i]);
        size[p]+=size[to[i]];
    }
}
int main(){
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);
    scanf("%d%d",&n,&m);
    fo(i,1,n){
        int fa;
        scanf("%d%d",&fa,&w[i]);
        if(fa)insert(fa,i);
        else a[++a[0]]=i;
    }
    fo(i,1,a[0])dfs(a[i]);
    fo(i,0,n)fo(j,0,m+1)f[i][j]=-inf;
    f[1][0]=0;
    fo(i,1,n)fo(j,0,m){
        int p=b[i];
        if(f[i+1][j+1]<f[i][j]+w[p]){
            f[i+1][j+1]=f[i][j]+w[p];
            g[i+1][j+1]=i;
            h[i+1][j+1]=j;
        }
        if(f[i+size[p]][j]<f[i][j]){
            f[i+size[p]][j]=f[i][j];
            g[i+size[p]][j]=i;
            h[i+size[p]][j]=j;
        }
        if(f[i+size[p]][j+1]<f[i][j]+w[p]){
            f[i+size[p]][j+1]=f[i][j]+w[p];
            g[i+size[p]][j+1]=i;
            h[i+size[p]][j+1]=j;
        }
    }
    printf("%dn",f[n+1][m]);
    if(m>=100)return 0;
    a[0]=0;
    int x=n+1,y=m;
    while(g[x][y]){
        int nx=g[x][y],ny=h[x][y];
        if(y!=ny)a[++a[0]]=b[nx];
        x=nx;y=ny;
    }
    sort(a+1,a+a[0]+1);
    fo(i,1,a[0])printf("%dn",a[i]);
    return 0;
}

最后

以上就是甜甜海燕为你收集整理的【jzoj3418】【NOIP动态规划专题】【选课】【树型依赖动态规划】的全部内容,希望文章能够帮你解决【jzoj3418】【NOIP动态规划专题】【选课】【树型依赖动态规划】所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(33)

评论列表共有 0 条评论

立即
投稿
返回
顶部