zoukankan      html  css  js  c++  java
  • Acwing 286.选课 (树上依赖背包)

    题目

    学校实行学分制。

    每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分。

    学校开设了 N 门的选修课程,每个学生可选课程的数量 M 是给定的。

    学生选修了这 M 门课并考核通过就能获得相应的学分。

    在选修课程中,有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其他的一些课程的基础上才能选修。

    例如《Windows程序设计》必须在选修了《Windows操作基础》之后才能选修。

    我们称《Windows操作基础》是《Windows程序设计》的先修课。

    每门课的直接先修课最多只有一门。

    两门课可能存在相同的先修课。

    你的任务是为自己确定一个选课方案,使得你能得到的学分最多,并且必须满足先修条件。

    假定课程之间不存在时间上的冲突。

    输入格式
    输入文件的第一行包括两个整数N、M(中间用一个空格隔开)其中1≤N≤300,1≤M≤N。

    接下来N行每行代表一门课,课号依次为1,2,…,N。

    每行有两个数(用一个空格隔开),第一个数为这门课先修课的课号(若不存在先修课则该项为0),第二个数为这门课的学分。

    学分是不超过10的正整数。

    输出格式
    输出一个整数,表示学分总数。

    输入样例:
    7 4
    2 2
    0 1
    0 4
    2 1
    7 1
    7 6
    2 2
    输出样例:
    13

    思路

    这个问题和那道上司的舞会很像,但又很不一样。其一,这个问题里面,我们不只有一棵树,所有的依赖关系可能是由森林的形式给出,其二,这些课之间的依赖关系如何处理。那么对于第一个问题来说,我们可以利用一个图论里面常用的思路,建一个超级源点,然后只需要求0点的dp值就好了。对于第二个点的话,我们可以把一个点下悬挂的n棵子树看做是n组的背包,每组背包里面的物品体积是1到m-1,然后我们做一次分组背包,但是要注意做背包的时候要在总体积上减去1,保留父亲的位置,以保障依赖关系。

    代码实现

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<map>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    using namespace std;
    #define rep(i,f_start,f_end) for (int i=f_start;i<=f_end;++i)
    #define per(i,n,a) for (int i=n;i>=a;i--)
    #define MT(x,i) memset(x,i,sizeof(x) )
    #define rev(i,start,end) for (int i=0;i<end;i++)
    #define inf 0x3f3f3f3f
    #define mp(x,y) make_pair(x,y)
    #define lowbit(x) (x&-x)
    #define MOD 1000000007
    #define exp 1e-8
    #define N 1000005 
    #define fi first 
    #define se second
    #define pb push_back
    typedef long long ll;
    typedef pair<int ,int> PII;
    typedef pair<int ,PII> PIII;
    ll gcd (ll a,ll b) {return b?gcd (b,a%b):a; }
    inline int read() {
        char ch=getchar(); int x=0, f=1;
        while(ch<'0'||ch>'9') {
            if(ch=='-') f = -1;
            ch=getchar();
        } 
        while('0'<=ch&&ch<='9') {
            x=x*10+ch-'0';
            ch=getchar();
        }   return x*f;
    }
    
    const int maxn=310;
    int  n,m;
    vector <int > v[maxn];
    int w[maxn];
    int f[maxn][maxn];   //f[root][m]
    
    void dfs (int u) {
        rev (i,0,v[u].size ()) {
            int son=v[u][i];
            dfs (son);
            
            per (j,m-1,0) {
                rep (k,1,j) {
                    f[u][j]=max (f[u][j],f[u][j-k]+f[son][k]);
                }
            }
        }
        per (i,m,1) {
            f[u][i]=f[u][i-1]+w[u];
        }
        f[u][0]=0;
    }
    
    int main () {
        cin>>n>>m;
        rep (i,1,n) {
           int a;
           cin>>a>>w[i];
           v[a].pb (i);
        }
        m++;
        dfs (0);
    
        cout<<f[0][m]<<endl;
    
        return 0;
    }
    
  • 相关阅读:
    十、Compose命令
    九、compose入门
    JS数组中,两两比较的算法,为了获取重复的值,并在php数组中,使用这种倒三角算法
    题目重复度检测---四种相似度检测的方案+PHP改进计算字符串相似度的函数similar_text()、levenshtein()
    js让文字一个个出现
    客户总想让页面炫酷起来-----怎么炫酷呢?---使用css3的东西或者其animate.css
    关于git的总结:git知识大全,命令行操作,vscode操作
    defer和async的区别
    dom和bom的区别,以及三类偏移属性(JS运动方法中,经常会涉及到这些位置信息)
    认真的对待flex,Flex模型和Flex属性思维导图,以及自己的记忆方法--jaf和aof
  • 原文地址:https://www.cnblogs.com/hhlya/p/13445307.html
Copyright © 2011-2022 走看看