洛谷 P2014 选课

来源:互联网 发布:淘宝双11如何抢购 编辑:程序博客网 时间:2024/04/29 04:08

题面

题意

给出n个课程,并选择m个,修一个课程可能要先修另外一个课程,修完后可获得一些学分,问学分的最大值是多少.

分析

这是一棵森林,因为无法记录此时的状态,所以难做.
可以将森林的顶点连到一个总根上,将森林变成一棵大树,记录每个点的最左儿子和右兄弟,然后从根节点开始DFS.
每个点只有两种选择:
1.不修这门,则DFS其右兄弟.
2.修这门,则DFS它最左儿子和右兄弟,并枚举分给他们的课程数.

代码

#include<iostream>#include<cstdio>#include<cstring>#define N 3100using namespace std;int n,m,num[N],dp[N][N],bb;struct Node{    Node()    {        bro=son=-1;    }    int num,son,bro;};Node node[N*2];inline void add(int u,int v,int w){    node[u].num=w;    node[u].bro=node[v].son;    node[v].son=u;}int dfs(int now,int sy){    if(now==-1||!sy) return 0;    if(dp[now][sy]!=-1) return dp[now][sy];    int i,j,res=dfs(node[now].bro,sy);    bool ze=now;    for(i=0;i<=sy-ze;i++)    {        res=max(res,node[now].num+dfs(node[now].son,i)+dfs(node[now].bro,sy-ze-i));    }    dp[now][sy]=res;    return res;}int main(){    register int i,j,p,q;    cin>>n>>m;    memset(dp,-1,sizeof(dp));    for(i=1;i<=n;i++)    {        scanf("%d%d",&p,&q);        add(i,p,q);    }    cout<<dfs(0,m);}