CH5402 选课
Posted sahdsg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CH5402 选课相关的知识,希望对你有一定的参考价值。
https://ac.nowcoder.com/acm/contest/1044/B
题目
学校实行学分制。
每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分。
学校开设了 N 门的选修课程,每个学生可选课程的数量 M 是给定的。
学生选修了这 M 门课并考核通过就能获得相应的学分。
在选修课程中,有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其他的一些课程的基础上才能选修。
例如《Windows程序设计》必须在选修了《Windows操作基础》之后才能选修。
我们称《Windows操作基础》是《Windows程序设计》的先修课。
每门课的直接先修课最多只有一门。
两门课可能存在相同的先修课。
你的任务是为自己确定一个选课方案,使得你能得到的学分最多,并且必须满足先修条件。
假定课程之间不存在时间上的冲突。
题解
设$dp[r][c]$为以$r$为根,选择$c$门课的最多学分
那么
[dp[r][c]=maxleft{dp[s_i][c_i]|(sum_{i=1}^{p} c_i)=c-1}+v[r]]
然而这个式子看起来像是废话,只靠这个是不能写出时限内的转移的($O(2^n)$)
还是需要利用背包,考虑某个节点的n个子树,把上一个式子扩展一下
[dp[r][cnt][c]=max{dp[r][cnt-1][c-c_i]+dp[s_i][n_s][c_i]}+v[r]],可以滚动优化[cnt],枚举$c_s$,时间复杂度$O(n*m*m)$
AC代码
#include<cstdio> #include<cstring> #include<algorithm> #define REP(i,a,b) for(register int i=(a); i<(b); i++) #define REPE(i,a,b) for(register int i=(a); i<=(b); i++) #define PERE(i,a,b) for(register int i=(a); i>=(b); i--) using namespace std; int n,m; int hd[307], nxt[307], to[307], e=0, v[307]; inline void adde(int a, int b) { nxt[e]=hd[a]; hd[a]=e; to[e]=b; e++; } int dp[307][307]; void calc(int r) { for(int i=hd[r]; ~i; i=nxt[i]) { int s=to[i]; calc(s); PERE(c,m,0) REPE(k,0,c) { dp[r][c]=max(dp[r][c],dp[r][c-k]+dp[s][k]); } } if(r) PERE(c,m,1) { dp[r][c]=dp[r][c-1]+v[r]; } } int main() { memset(dp,0,sizeof(dp)); memset(hd,-1,sizeof hd); scanf("%d%d", &n, &m); REPE(i,1,n) { int a; scanf("%d%d", &a, &v[i]); adde(a,i); } calc(0); printf("%d ", dp[0][m]); }
以上是关于CH5402 选课的主要内容,如果未能解决你的问题,请参考以下文章
使用 ATmega16A 的 MAX5402 数字电位器的 SPI 配置
hdu5402:Travelling Salesman Problem