zoukankan      html  css  js  c++  java
  • Luogu P2014 选课 题解报告

    题目传送门

    【题目大意】

    有n门选修课,每一门课都有固定的学分$S_i$,每个学生可以选m门课。有些选修课有先修课,每一门课最多只有一门先修课,求能获得的最多学分。

    【思路解析】

    设f[x][t]表示在以x结点为根的子树中选t门课能获得的最大学分,x的子结点集合为son[x],子结点个数为p,且对于x的第i个子结点son[i],以其为根结点的子树中选课数量为$C_i$,则转移方程为:$$f[x][t]=max(sum_{i=1}^{p}f[son[i]][c[i]])+s[i](满足sum_{i=1}^{p}c[i]=t-1)$$这个方程其实是一个分组背包模型,有p组物品,每组物品有t-1个,其中第i组的第j个物品体积为j,价值为f[son[i]][j],背包的容积为t-1。

    【代码实现】

     1 #include<bits/stdc++.h>
     2 #define rg register
     3 #define go(i,a,b) for(rg int i=a;i<=b;i++)
     4 #define back(i,a,b) for(rg int i=a;i>=b;i--)
     5 #define ll long long
     6 #define mem(a,b) memset(a,b,sizeof(a))
     7 using namespace std;
     8 const int N=302;
     9 vector<int> son[N];
    10 int f[N][N],n,m,s[N];
    11 void dp(int x){
    12     f[x][0]=0;
    13     int size=son[x].size();
    14     go(i,0,size-1){//循环子结点(物品)
    15         int y=son[x][i];
    16         dp(y);
    17         back(t,m,0) back(j,t,0)
    18 //倒叙循环当前选课总门数(当前背包体积)
    19 //循环更深子树上的选课门数(组内物品),此处使用倒序是为了正确处理组内体积为0的物品
    20             if(t-j>=0) f[x][t]=max(f[x][t],f[x][t-j]+f[y][j]);
    21     }
    22     if(x!=0)//x不为0时,选修x本身要占掉一门课,并获得相应学分
    23         back(t,m,1) f[x][t]=f[x][t-1]+s[x];
    24     return;
    25 }
    26 int main(){
    27     scanf("%d%d",&n,&m);
    28     go(i,1,n){
    29         int fa;
    30         scanf("%d%d",&fa,&s[i]);
    31         son[fa].push_back(i);
    32     }
    33     mem(f,0);
    34     dp(0);
    35     printf("%d
    ",f[0][m]);
    36     return 0;
    37 }
    代码戳这里
  • 相关阅读:
    0621回顾与总结
    0614--演示
    学习进度条
    实验四主存空间的分配和回收
    学术诚信和职业道德
    《构建之法》读第六、第七章有感
    0422 Step2-FCFS调度
    java 版的复利计算器(张俊毅 周修文)
    复利程序(c语言)(张俊毅 周修文)
    《构建之法》第4章
  • 原文地址:https://www.cnblogs.com/THWZF/p/11002226.html
Copyright © 2011-2022 走看看