选课

选课

https://ac.nowcoder.com/acm/problem/51179

题意:
你有n门课程,你可以选择m门课选修,有的课程有先修课,每一门课程都有学分,求你可获得的最大学分为多少?

思路:
树状dp
没先修课的与0节点连接,有先修课的与先修课连接,这样就是0节点为根的一棵树了。
dp[i][j]表示以i节点为根的子树且选择了i时共选择j门课程的最大学分,这样就满足了先修课的条件。
se[i]表示以i为根的子树的节点数。
根节点u,子节点v:
dp[u][r+l]=max(dp[u][r+l],dp[u][l]+dp[v][r]);
结果为dp[0][m];(0节点不是一门课,一开始m要+1,因为0节点一定会被选)

代码:

#include <bits/stdc++.h>
typedef long long ll;

using namespace std;

const ll inf=1000000007;

inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}

int k[305], dp[305][305], se[305], m;

vector<int> g[305];

void dfs(int v)
{
    se[v]=1;
    dp[v][1]=k[v];
    for(int i=0;i<g[v].size();i++)
    {
        dfs(g[v][i]);
        for(int l=min(se[v],m);l>=1;l--)
        {
            for(int r=0;r<=min(se[g[v][i]],m);r++)
            {
                if(l+r<=m)
                {
                    dp[v][r+l]=max(dp[v][r+l],dp[v][l]+dp[g[v][i]][r]);
                }
            }
        }
        se[v]+=se[g[v][i]];
    }
}

int main()
{
    int n;
    scanf("%d%d",&n,&m);
    m++;
    for(int i=1;i<=n;i++)
    {
        int u, t;
        scanf("%d %d",&u,&t);
        g[u].push_back(i);
        k[i]=t;
    }
    dfs(0);
    printf("%d\n",dp[0][m]);
    return 0;
}
全部评论

相关推荐

点赞 评论 收藏
分享
11-28 17:58
门头沟学院 Java
美团 JAVA开发 n×15.5
牛客786276759号:百度现在晋升很难的 而且云这块的业务没美团好 你看百度股价都跌成啥样了
点赞 评论 收藏
分享
评论
5
收藏
分享
牛客网
牛客企业服务