• Vijos 1180 (树形DP+背包)


    题目链接https://vijos.org/p/1180

    题目大意:选课。只有根课选了才能选子课,给定选课数m, 问最大学分多少。

    解题思路

    树形背包。cost=1。

    且有个虚根0,取这个虚根也要cost,所以最后的结果是dp[0][m+1]。

    本题是cost=1的特殊背包问题,在两个for循环上有一个优化。

    for(f+1...j....cost)

      for(1....k...j-cost)

    其中f为当前已经dfs子结点个数。之所以+1,是因为根要预留一个空间。

    f+=dfs(t),dfs(t)返回的是子点t的f+1。

    其实可以直接把f+1写成m+1, 不过要多好多次没必要的循环。

    这种写法在POJ 1155点数量庞大时,将起决定性作用。

    #include "iostream"
    #include "cstdio"
    #include "cstring"
    using namespace std;
    #define maxn 305
    int n,m,root,x;
    int dp[maxn][maxn],head[maxn],w[maxn],tol;
    struct Edge
    {
        int to,next;
    }e[maxn];
    void addedge(int u,int v)
    {
        e[tol].to=v;
        e[tol].next=head[u];
        head[u]=tol++;
    }
    int dfs(int root)
    {
        int i=root,f=0,cost=1;
        for(int i=cost;i<=m;i++) dp[root][i]=w[root];
        for(int a=head[root];a!=-1;a=e[a].next)
        {
            int t=e[a].to;
            f+=dfs(t);
            for(int j=f+1; j>=cost; j--)
                for(int k=1; k<=j-cost; k++)
                    dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[t][k]);
        }
        return f+cost; //¸ùÒ²ÏûºÄ1
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        scanf("%d%d",&n,&m);
        memset(head,-1,sizeof(head));
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&x,&w[i]);
            addedge(x,i);
        }
        dfs(0);
        printf("%d
    ",dp[0][m+1]);
    }

    Accepted, time = 22 ms, mem = 924 KiB, score = 100

  • 相关阅读:
    chrom插件开发
    实验7
    第六次实验报告
    c++第五次实验报告
    c++第四次实验报告
    c++第三次实验报告
    C++第二次实验
    c++第一次作业
    HttpWebRequest调用webservice
    树状组织结构-Tree
  • 原文地址:https://www.cnblogs.com/neopenx/p/4032015.html
Copyright © 2020-2023  润新知