JZOJ 3418. 【NOIP动态规划专题】选课
2017-08-11 16:27
267 查看
Description
大学里实行学分。每门课程都有一定的学分,学生只要选修了这门课,并通过考核就能获得相应的学分。学生最后的学分是他各门课学分的总和。每个学生都要选择规定数量的课程。其中有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其他的一些课程的基础上才能选修。例如,《剥皮术》就必须在选修了《屠龙术》后才能选修。
我们称《屠龙术》是《剥皮术》的先修课。
每门课的直接先修课最多之有一门。两门课也可能存在相同的先修课。
每门课都有一个课号,课号依次是1,2,3……。以下表为例说明。
课号 先修课号 学分
1 无 1
2 1 1
3 2 3
4 无 3
5 2 4
上表中1是2的先修课,即如果要选修2,则1必须已被选过。
同样,要选修3,那么1和2都一定被选修过。
每个学生可选的课程总数是一定的,请找出一种方案,使得到的总学分最多。
Input
第一行包括两个正整数M、N(中间一个空格),其中M表示总课程数(1<=M<=1000),N表示每个学生最多可选的课程总数。(1<=N<=M)。以下M行每行代表一门课,课号依次是1,2,…,M。每行两个数,第一个数为这门课的直接先修课的课号(若不存在则为0),第二个数为该门课的学分。学分是不超过10的正整数。
测试数据保证学生能够选满N门课。
Output
第一行只有一个数,即最多可得的学分。如果M<=99,则以下N行每行一个数,表示学生所选的课程的课号,课号按升序排列。
如果M>=100,则不必输出具体方案。
数据保证只有唯一的正确输出。
Sample Input
7 42 2
0 1
0 4
2 1
7 1
7 6
2 2
Sample Output
132
3
6
7
Data Constraint
1<=M<=1000Solution
先按照题目所描述的关系建树(多叉树转化成二叉树),以方便处理。多叉转二叉 的方法: 一个点的左儿子存其真儿子,右儿子存其兄弟节点 。
接着就是我们的树形DP了——
设 F[i][j] 表示当前做到第 i 门课、在以其为根的子树中选了 j 门课的最大学分。转移为:F[i][j]=Max{F[l[i]][k−1]+F[r[i]][j−k]}(1≤k≤j,l,r为其左右儿子)
统计具体方案就用一个邻接表储存,当最优方案更新时随之更新即可。
总时间复杂度为 O(M2) 。
Code
#include<cstdio> #include<algorithm> using namespace std; const int N=1001,M=101; int m,n,ans; int a ,b ,l ,r ; int f ,g[M][M][M]; inline int read() { int X=0,w=1; char ch=0; while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();} while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar(); return X*w; } inline void dfs(int x,int y) { if(!x || !y) return; dfs(r[x],y); if(m<=99) for(int i=0;i<=g[r[x]][y][0];i++) g[x][y][i]=g[r[x]][y][i]; int sum=f[r[x]][y]; for(int i=1;i<=y;i++) { dfs(l[x],i-1); dfs(r[x],y-i); if(f[l[x]][i-1]+f[r[x]][y-i]+a[x]>sum) { sum=f[l[x]][i-1]+f[r[x]][y-i]+a[x]; if(m<=99) { g[x][y][g[x][y][0]=1]=x; for(int j=1;j<=g[l[x]][i-1][0];j++) g[x][y][++g[x][y][0]]=g[l[x]][i-1][j]; for(int j=1;j<=g[r[x]][y-i][0];j++) g[x][y][++g[x][y][0]]=g[r[x]][y-i][j]; } } } f[x][y]=sum; } int main() { m=read(),n=read(); for(int i=1;i<=m;i++) { int x=read(); if(!l[x]) l[x]=i; else r[b[x]]=i; a[b[x]=i]=read(); } dfs(l[0],n); printf("%d\n",f[l[0]] ); if(m<=99) { for(int i=1;i<=n;i++) b[i]=g[l[0]] [i]; sort(b+1,b+1+n); for(int i=1;i<=n;i++) printf("%d\n",b[i]); } return 0; }
相关文章推荐
- 【jzoj3418】【NOIP动态规划专题】【选课】【树型依赖动态规划】
- JZOJ 4.1 C组 【NOIP动态规划专题】电子眼
- jzoj P1029【NOIP动态规划专题】电子眼
- JZOJ3418. 【NOIP动态规划专题】选课(2017.8DP&贪心专题)
- JZOJ8.11(C组)【NOIP动态规划专题】采药2 (Standard IO)
- 2540. 【NOIP动态规划专题】采药2 (Standard IO)
- 【NOIP动态规划专题】采药2
- 2.24 --- 2.25 动态规划专题小测 及 NOIP 2008 模拟 总结
- 【NOIP动态规划专题】采药2 (Standard IO)
- 【NOIP动态规划专题】最大利润
- JZOJsenior1168.【NOIP动态规划专题】合唱队形
- NOIP专题复习——专题二:动态规划基础
- 高中OJ1771. 【NOIP动态规划专题】烽火传递
- 动态规划专题:树上DP和状态压缩DP
- 动态规划专题:beginner
- 动态规划专题之----198. House Robber
- 动态规划专题:POJ 动态规划题目列表
- 动态规划专题讲义之最大连续子序列之和
- 动态规划 - 区间DP - NOIP 乘积最大
- [NOIP 2014复习]第三章:动态规划——NOIP历届真题回顾