【Leetcode】1494. Parallel Courses II

文章探讨了利用动态规划解决在线编程题目的课程选课问题,涉及二进制表示、前置课程关系和学期限制,时间复杂度为O(n*2^n),空间复杂度为O(2^n)。
摘要由CSDN通过智能技术生成

题目地址:

https://leetcode.com/problems/parallel-courses-ii/

给定 n n n门课,编号 1 ∼ n 1\sim n 1n,两个课程之间可能有前置关系,例如 u → v u\to v uv表示 u u u v v v的一门前置课程,想上 v v v必须先上完 u u u。每门课可能有多门前置课程。规定每学期最多上 k k k门课,并且每学期上的课里必须每一门的前置课程都已经修好(当然没有前置课程也可以)。问最少多少个学期可以将所有课都上完。题目保证课程不会产生环。

思路是动态规划。设课程编号从 0 0 0开始。设 f [ s ] f[s] f[s]是要上完课程的二进制表示是 s s s的情况下,最少需要多少个学期。那么 f [ 0 ] = 0 f[0]=0 f[0]=0。我们考虑 f [ s ] f[s] f[s]可以更新哪些状态。首先我们找到在状态 s s s下可以上哪些还没上过的课,设这些课的二进制表示为 t t t,然后遍历 t t t的所有非空子集,如果某子集 p p p 1 1 1的个数小于 k k k,那么这些课是可以在下个学期里上完的,从而 f [ s ] + 1 f[s]+1 f[s]+1可以用来更新 f [ s ∣ p ] f[s|p] f[sp]。最后返回 f [ 2 n − 1 ] f[2^n-1] f[2n1]即可。代码如下:

class Solution {
 public:
  int minNumberOfSemesters(int n, vector<vector<int>>& rs, int k) {
    vector<int> f(1 << n, n), pre(n);
    // 存一下每门课的前置课程是哪些
    for (auto& r : rs) pre[r[1] - 1] |= 1 << r[0] - 1;

    f[0] = 0;
    for (int i = 0; i < (1 << n); i++) {
      // 求一下当前已经上完的课是i的情况下,下学期可以上哪些课
      int can_take = 0;
      for (int j = 0; j < n; j++)
      	// 如果j的所有前置课程都包含在i内,那j是可以上的
        if ((pre[j] & i) == pre[j]) can_take |= 1 << j;
	  // 把已经上过的课排除掉
      can_take &= ~i;
      // 遍历p的所有子集。p - 1 & can_take是p的真子集里二进制表示最大的那个
      for (int p = can_take; p; p = p - 1 & can_take)
      	// 如果p的1的个数小于等于k,那么下学期可以选择上p的那些课
        if (__builtin_popcount(p) <= k) f[i | p] = min(f[i | p], f[i] + 1);
    }

    return f[(1 << n) - 1];
  }
};

时间复杂度 O ( n 2 n ) O(n2^n) O(n2n),空间 O ( 2 n ) O(2^n) O(2n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值