{"id":6982,"date":"2020-06-27T22:41:08","date_gmt":"2020-06-28T05:41:08","guid":{"rendered":"https:\/\/zxi.mytechroad.com\/blog\/?p=6982"},"modified":"2020-06-28T00:06:10","modified_gmt":"2020-06-28T07:06:10","slug":"leetcode-1494-parallel-courses-ii","status":"publish","type":"post","link":"https:\/\/zxi.mytechroad.com\/blog\/dynamic-programming\/leetcode-1494-parallel-courses-ii\/","title":{"rendered":"\u82b1\u82b1\u9171 LeetCode 1494. Parallel Courses II"},"content":{"rendered":"\n<p>Given the integer&nbsp;<code>n<\/code>&nbsp;representing the number of courses at some university labeled from&nbsp;<code>1<\/code>&nbsp;to&nbsp;<code>n<\/code>, and the array&nbsp;<code>dependencies<\/code>&nbsp;where&nbsp;<code>dependencies[i] = [x<sub>i<\/sub>, y<sub>i<\/sub>]<\/code>&nbsp;&nbsp;represents a prerequisite relationship, that is, the course&nbsp;<code>x<sub>i<\/sub><\/code>&nbsp;must be taken before the course&nbsp;<code>y<sub>i<\/sub><\/code>. &nbsp;Also, you are given the&nbsp;integer&nbsp;<code>k<\/code>.<\/p>\n\n\n\n<p>In one semester you can take&nbsp;<strong>at most<\/strong>&nbsp;<code>k<\/code>&nbsp;courses as long as you have taken all the prerequisites for the courses you are taking.<\/p>\n\n\n\n<p><em>Return the minimum number of semesters to take all courses<\/em>.&nbsp;It is guaranteed that you can take all courses in some way.<\/p>\n\n\n\n<p><strong>Example 1:<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/assets.leetcode.com\/uploads\/2020\/05\/22\/leetcode_parallel_courses_1.png\" alt=\"\"\/><\/figure>\n\n\n\n<pre class=\"wp-block-preformatted;crayon:false\"><strong>Input:<\/strong> n = 4, dependencies = [[2,1],[3,1],[1,4]], k = 2\n<strong>Output:<\/strong> 3 \n<strong>Explanation:<\/strong> The figure above represents the given graph. In this case we can take courses 2 and 3 in the first semester, then take course 1 in the second semester and finally take course 4 in the third semester.\n<\/pre>\n\n\n\n<p><strong>Example 2:<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/assets.leetcode.com\/uploads\/2020\/05\/22\/leetcode_parallel_courses_2.png\" alt=\"\"\/><\/figure>\n\n\n\n<pre class=\"wp-block-preformatted;crayon:false\"><strong>Input:<\/strong> n = 5, dependencies = [[2,1],[3,1],[4,1],[1,5]], k = 2\n<strong>Output:<\/strong> 4 \n<strong>Explanation:<\/strong> The figure above represents the given graph. In this case one optimal way to take all courses is: take courses 2 and 3 in the first semester and take course 4 in the second semester, then take course 1 in the third semester and finally take course 5 in the fourth semester.\n<\/pre>\n\n\n\n<p><strong>Example 3:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted;crayon:false\"><strong>Input:<\/strong> n = 11, dependencies = [], k = 2\n<strong>Output:<\/strong> 6\n<\/pre>\n\n\n\n<p><strong>Constraints:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code>1 &lt;= n &lt;= 15<\/code><\/li><li><code>1 &lt;= k &lt;= n<\/code><\/li><li><code>0 &lt;=&nbsp;dependencies.length &lt;= n * (n-1) \/ 2<\/code><\/li><li><code>dependencies[i].length == 2<\/code><\/li><li><code>1 &lt;= x<sub>i<\/sub>, y<sub>i<\/sub>&nbsp;&lt;= n<\/code><\/li><li><code>x<sub>i<\/sub>&nbsp;!= y<sub>i<\/sub><\/code><\/li><li>All prerequisite relationships are distinct, that is,&nbsp;<code>dependencies[i] != dependencies[j]<\/code>.<\/li><li>The given graph is a directed acyclic graph.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Solution: DP<\/strong> <strong>\/ Bitmask<\/strong><\/h2>\n\n\n\n<p>NOTE: This is a NP problem, any polynomial-time algorithm is incorrect otherwise P = NP.<\/p>\n\n\n\n<p>Variant 1:<br>dp[m] := whether state m is reachable, where m is the bitmask of courses studied.<br>For each semester, we enumerate all possible states from 0 to 2^n &#8211; 1, if that state is reachable, then we choose c (c &lt;= k) courses from n and check whether we can study those courses.<br>If we can study those courses, we have a new reachable state, we set dp[m | courses] = true.<\/p>\n\n\n\n<p>Time complexity: O(n*2^n*2^n) = O(n*n^4) &lt;&#8211; This will be much smaller in practice.<br>and can be reduced to O(n*3^n).<br>Space complexity: O(2^n)<\/p>\n\n\n\n<div class=\"responsive-tabs\">\n<h2 class=\"tabtitle\">C++<\/h2>\n<div class=\"tabcontent\">\n\n<pre lang=\"C++\">\n\/\/ Author: Huahua, 52 ms, 14.5 MB\nclass Solution {\npublic:\n  int minNumberOfSemesters(int n, vector<vector<int>>& dependencies, int k) {    \n    const int S = 1 << n;\n    vector<int> deps(n); \/\/ deps[i] = dependency mask for course i.\n    for (const auto& d : dependencies)\n      deps[d[1] - 1] |= 1 << (d[0] - 1);    \n    \/\/ dp(i)[s] := reachable(s) at semester i.\n    vector<int> dp(S);\n    dp[0] = 1;\n    for (int d = 1; d <= n; ++d) { \/\/ at most n semesters.\n      vector<int> tmp(S); \/\/ start a new semesters.\n      for (int s = 0; s < S; ++s) {\n        if (!dp[s]) continue; \/\/ not a reachable state.\n        int mask = 0;\n        for (int i = 0; i < n; ++i)\n          if (!(s &#038; (1 << i)) &#038;&#038; (s &#038; deps[i]) == deps[i]) \n            mask |= (1 << i);\n        \/\/ Prunning, take all.\n        if (__builtin_popcount(mask) <= k) {\n          tmp[s | mask] = 1;         \n        } else {\n          \/\/ Try all subsets. \n          for (int c = mask; c; c = (c - 1) &#038; mask)\n            if (__builtin_popcount(c) <= k) {\n              tmp[s | c] = 1;\n            }\n        }\n        if (tmp.back()) return d;\n      }\n      dp.swap(tmp);      \n    }\n    return -1;\n  }\n};\n\n<\/pre>\n<\/div><\/div>\n\n\n\n<p>Variant 2:<br>dp[m] := min semesters to reach state m.<br>dp[m | c] = min{dp[m | c], dp[m] + 1}, if we can reach m | c from m.<br>This allows us to get rid of enumerate n semesters.<br>Time complexity: O(2^n*2^n) &lt;-- This will be much smaller in practice.<br>and can be reduced to O(3^n).<br>Space complexity: O(2^n)<\/p>\n\n\n\n<div class=\"responsive-tabs\">\n<h2 class=\"tabtitle\">C++<\/h2>\n<div class=\"tabcontent\">\n\n<pre lang=\"C++\">\n\/\/ Author: Huahua, 16 ms, 8.5 MB\nclass Solution {\npublic:\n  int minNumberOfSemesters(int n, vector<vector<int>>& dependencies, int k) {\n    const int kInf = 1e9;\n    const int S = 1 << n;\n    vector<int> deps(n); \/\/ deps[i] = dependency mask for course i.\n    for (const auto& d : dependencies)\n      deps[d[1] - 1] |= 1 << (d[0] - 1);    \n    \/\/ dp[m] := min semesters to reach state m.\n    vector<int> dp(S, kInf);\n    dp[0] = 0;\n    for (int s = 0; s < S; ++s) {\n      if (dp[s] == kInf) continue; \/\/ not reachable.\n      \/\/ Generate a mask of courses we can study under state s.\n      int mask = 0;\n      for (int i = 0; i < n; ++i)\n        if (!(s &#038; (1 << i)) &#038;&#038; (s &#038; deps[i]) == deps[i])\n          mask |= (1 << i);\n      \/\/ Prunning, take all.\n      if (__builtin_popcount(mask) <= k) {\n        dp[s | mask] = min(dp[s | mask], dp[s] + 1);       \n      } else {\n        \/\/ Try all subsets.\n        for (int c = mask; c; c = (c - 1) &#038; mask)\n          if (__builtin_popcount(c) <= k)\n            dp[s | c] = min(dp[s | c], dp[s] + 1);\n      }\n      \/\/ Early termination?\n      if (dp.back() != kInf) return dp.back();\n    }\n    return dp.back();\n  }\n};\n<\/pre>\n<\/div><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Given the integer&nbsp;n&nbsp;representing the number of courses at some university labeled from&nbsp;1&nbsp;to&nbsp;n, and the array&nbsp;dependencies&nbsp;where&nbsp;dependencies[i] = [xi, yi]&nbsp;&nbsp;represents a prerequisite relationship, that is, the course&nbsp;xi&nbsp;must&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[46],"tags":[621,18,217,623,589],"class_list":["post-6982","post","type-post","status-publish","format-standard","hentry","category-dynamic-programming","tag-bitmask","tag-dp","tag-hard","tag-np","tag-state-compression","entry","simple"],"_links":{"self":[{"href":"https:\/\/zxi.mytechroad.com\/blog\/wp-json\/wp\/v2\/posts\/6982","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zxi.mytechroad.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zxi.mytechroad.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zxi.mytechroad.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zxi.mytechroad.com\/blog\/wp-json\/wp\/v2\/comments?post=6982"}],"version-history":[{"count":9,"href":"https:\/\/zxi.mytechroad.com\/blog\/wp-json\/wp\/v2\/posts\/6982\/revisions"}],"predecessor-version":[{"id":6992,"href":"https:\/\/zxi.mytechroad.com\/blog\/wp-json\/wp\/v2\/posts\/6982\/revisions\/6992"}],"wp:attachment":[{"href":"https:\/\/zxi.mytechroad.com\/blog\/wp-json\/wp\/v2\/media?parent=6982"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zxi.mytechroad.com\/blog\/wp-json\/wp\/v2\/categories?post=6982"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zxi.mytechroad.com\/blog\/wp-json\/wp\/v2\/tags?post=6982"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}