{"id":1030,"date":"2020-04-19T21:00:17","date_gmt":"2020-04-20T04:00:17","guid":{"rendered":"http:\/\/209.126.2.187\/?p=1030"},"modified":"2020-04-24T21:43:10","modified_gmt":"2020-04-25T04:43:10","slug":"state-compression-dp","status":"publish","type":"post","link":"https:\/\/nanzhou.cc\/index.php\/2020\/04\/19\/state-compression-dp\/","title":{"rendered":"State Compression DP"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>State compression is a common technique in some DP problems when number of states are limited and each state consists of bits, where each bit has specific physical meaning.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">OJ<\/h2>\n\n\n\n\n<table id=\"tablepress-11\" class=\"tablepress tablepress-id-11\">\n<thead>\n<tr class=\"row-1\">\n\t<td class=\"column-1\"><\/td><th class=\"column-2\">Trick<\/th><th class=\"column-3\">Difficulty<\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"row-striping row-hover\">\n<tr class=\"row-2\">\n\t<td class=\"column-1\"><a href=\"https:\/\/leetcode.com\/problems\/maximum-students-taking-exam\/\" target=\"_blank\" rel=\"noopener noreferrer\"> LC 1349. Maximum Students Taking Exam <\/a><\/td><td class=\"column-2\">DP State Compression + Bit Manipulation<\/td><td class=\"column-3\">6 points<\/td>\n<\/tr>\n<tr class=\"row-3\">\n\t<td class=\"column-1\"><a href=\"https:\/\/leetcode.com\/problems\/stickers-to-spell-word\/\" target=\"_blank\" rel=\"noopener noreferrer\"> LC 691. Stickers to Spell Word<\/a><\/td><td class=\"column-2\">DP State Compression <\/td><td class=\"column-3\">6-7 points<\/td>\n<\/tr>\n<tr class=\"row-4\">\n\t<td class=\"column-1\"><a href=\"https:\/\/leetcode.com\/problems\/number-of-ways-to-paint-n-3-grid\/\" target=\"_blank\" rel=\"noopener noreferrer\">LC 1411. Number of Ways to Paint N \u00d7 3 Grid<\/a><\/td><td class=\"column-2\">DP State Compression or Direct DP <\/td><td class=\"column-3\">6 points<\/td>\n<\/tr>\n<tr class=\"row-5\">\n\t<td class=\"column-1\"><a href=\"https:\/\/leetcode.com\/problems\/find-the-shortest-superstring\/\" target=\"_blank\" rel=\"noopener noreferrer\">LC 943. Find the Shortest Superstring<\/a><\/td><td class=\"column-2\">DP State Compression  + TSP<\/td><td class=\"column-3\">7 points<\/td>\n<\/tr>\n<tr class=\"row-6\">\n\t<td class=\"column-1\"><a href=\"m\/problems\/number-of-ways-to-wear-different-hats-to-each-other\/\" target=\"_blank\" rel=\"noopener noreferrer\"> LC 1434. Number of Ways to Wear Different Hats to Each Other<\/a><\/td><td class=\"column-2\">DP Knapsack + State Compression<\/td><td class=\"column-3\">6-7 points<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<!-- #tablepress-11 from cache -->\n\n\n\n<h2 class=\"wp-block-heading\">Details<\/h2>\n\n\n\n<h4 class=\"wp-block-heading\"><a rel=\"noreferrer noopener\" href=\"https:\/\/leetcode.com\/problems\/maximum-students-taking-exam\/\" target=\"_blank\">LC 1349. Maximum Students Taking Exam<\/a> <\/h4>\n\n\n\n<p>Difficulty: 6 points.<\/p>\n\n\n\n<p>We could use bit manipulation and state compression DP. For each row, when a slot has a student we consider the corresponding bit to be 1, so there are at most <code>2^n<\/code> states for each row. Some bit manipulation tricks are as following. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp\">\/\/ row curr does not contain adjacent students\n\/\/ row curr does not occupy '#'\n\/\/ forbidden[i] = 101101 for 'x.xx.x'\ninline bool ok(bitset&lt;8> const &amp;curr, int i) {\n    return (curr &amp; (curr >> 1)) == 0 &amp;&amp; (i >= 0 ? (forbidden[i] &amp; curr) == 0 : true);\n}\n\n\/\/ row curr and row prev does not contain diagonal students\ninline bool ok(bitset&lt;8> const &amp;curr, bitset&lt;8> const &amp;prev) {\n    return ((curr >> 1) &amp; prev) == 0 &amp;&amp; ((curr &lt;&lt; 1) &amp; prev) == 0;\n}<\/code><\/pre>\n\n\n\n<p>Then the DP state transformation is not difficult.  <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">alg[i][prev] = \n   max {curr.count() + alg[i + 1][curr] if ok(curr, prev) &amp;&amp; ok(curr, i) &amp;&amp; ok(prev, i - 1) for curr in [0, (1 &lt;&lt; n) - 1]}<\/code><\/pre>\n\n\n\n<p>Note that for the DP table related to previous state, we need to find answer by adding at least one state. However, here we know <code>alg[0][0]<\/code> will work since the first row won&#8217;t have conflicts with previous state <code>0<\/code>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><a rel=\"noreferrer noopener\" href=\"https:\/\/leetcode.com\/problems\/number-of-ways-to-paint-n-3-grid\/\" target=\"_blank\">LC 1411. Number of Ways to Paint N \u00d7 3 Grid<\/a> <\/h4>\n\n\n\n<p>Difficulty: 6 points.<\/p>\n\n\n\n<p>This problem can be solved efficiently in <code>log(n)<\/code> time, which is introduced in <a href=\"http:\/\/161.97.122.139\/index.php\/2020\/04\/12\/binary-exponentiation-dp-counting\/\">this post<\/a>. It is nice to mention as a follow up solution. <\/p>\n\n\n\n<p>The common answer will be State Compression for this kind of problem. The grid is of length 3, which means a grid has 27 states. We use a base 3 number integer to represent states, though we need to explicitly parse the physical meaning out of the integer (no base 2 tricks here).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">alg[i][prev] = sum { alg[i + 1][curr] if ok(curr, prev) &amp;&amp; ok(prev) &amp;&amp; ok(curr) for curr in [0, 27]<\/code><\/pre>\n\n\n\n<p>Note that for the DP table related to previous state, we need to find answer by adding at least one state.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp\">ll result = 0;\nfor (int prev = 0; prev &lt; 27; ++prev) {\n    result += alg[1][prev];\n    result %= MOD;\n}\nreturn result;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><a rel=\"noreferrer noopener\" href=\"https:\/\/leetcode.com\/problems\/find-the-shortest-superstring\/\" target=\"_blank\">LC 943. Find the Shortest Superstring<\/a><\/h4>\n\n\n\n<p>Difficulty: 7 points.<\/p>\n\n\n\n<p>The problem is hard, since it is hard to detect it is actually a TSP problem.<\/p>\n\n\n\n<p>Think in this way. Given a permutation of strings, if between two adjacent strings there are overlaps, we could leverage them and shorten the total length. For example, <code>\"catg\" + \"atgcatc\"<\/code> can be <code>\"c\" + \"atg\" + \"catc\"<\/code>. We want to maximize the overlaps. In the other way, if we think the non-overlapping chars as the cost to stick the current word to the previous one. The problem becomes find out a permutation with lowest cost, which is a TSP problem. <\/p>\n\n\n\n<p>Regarding the TSP problem, for any permutation, the cost starting from index j is determined by the visited indexes and the previous index i.  Visited indexes could use the State Compression technique.  <\/p>\n\n\n\n<p>The problem also needs to output a path. So we uses another table to store our best choices at each state. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">alg[visited][prev] = \n  min {alg[visited | 1 &lt;&lt; j][j] + dist[prev][j] if ((1 &lt;&lt; j) &amp; visited == 0 &amp;&amp; (1 &lt;&lt; prev) &amp; visited > 0) for j in [0, n - 1]}\n\nchoices[visited][prev] = \n  argmin {alg[visited | 1 &lt;&lt; j][j] + dist[prev][j] if ((1 &lt;&lt; j) &amp; visited == 0 &amp;&amp; (1 &lt;&lt; prev) &amp; visited > 0) for j in [0, n - 1]}<\/code><\/pre>\n\n\n\n<p>Note that for the DP table related to previous state, we need to find answer by adding at least one state.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp\">int min_ = INT_MAX;\nint curr = -1;\nfor (int i = 0; i &lt; n; ++i) {\n    if (alg[1 &lt;&lt; i][i] + A[i].size() &lt; min_) {\n        min_ = alg[1 &lt;&lt; i][i] + A[i].size();\n        curr = i;\n    }\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Summary State compression is a common technique in some DP problems when number of states are limited and each state consists of bits, where each bit has specific physical meaning. OJ Details LC 1349. Maximum Students Taking Exam Difficulty: 6 points. We could use bit manipulation and state compression DP. For each row, when a&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[48,61],"tags":[],"class_list":["post-1030","post","type-post","status-publish","format-standard","hentry","category-alg","category-dp-state-compression"],"_links":{"self":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts\/1030","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/comments?post=1030"}],"version-history":[{"count":10,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts\/1030\/revisions"}],"predecessor-version":[{"id":1058,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts\/1030\/revisions\/1058"}],"wp:attachment":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/media?parent=1030"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/categories?post=1030"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/tags?post=1030"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}