<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>optimization Archives - Huahua&#039;s Tech Road</title>
	<atom:link href="https://zxi.mytechroad.com/blog/tag/optimization/feed/" rel="self" type="application/rss+xml" />
	<link>https://zxi.mytechroad.com/blog/tag/optimization/</link>
	<description></description>
	<lastBuildDate>Wed, 29 Jul 2020 16:40:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.0.8</generator>

<image>
	<url>https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/cropped-photo-32x32.jpg</url>
	<title>optimization Archives - Huahua&#039;s Tech Road</title>
	<link>https://zxi.mytechroad.com/blog/tag/optimization/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>花花酱 LeetCode 1531. String Compression II</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-1531-string-compression-ii/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-1531-string-compression-ii/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 26 Jul 2020 20:01:53 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[encoding]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[run length]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=7169</guid>

					<description><![CDATA[<p>Run-length encoding&#160;is a string compression method that works by&#160;replacing consecutive identical characters (repeated 2 or more times) with the concatenation of the character and the&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-1531-string-compression-ii/">花花酱 LeetCode 1531. String Compression II</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="花花酱 LeetCode 1531. String Compression II - 刷题找工作 EP347" width="500" height="281" src="https://www.youtube.com/embed/UIK00l_AiPQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div></figure>



<p><a href="http://en.wikipedia.org/wiki/Run-length_encoding">Run-length encoding</a>&nbsp;is a string compression method that works by&nbsp;replacing consecutive identical characters (repeated 2 or more times) with the concatenation of the character and the number marking the count of the characters (length of the run). For example, to compress the string&nbsp;<code>"aabccc"</code>&nbsp;we replace&nbsp;<code>"aa"</code>&nbsp;by&nbsp;<code>"a2"</code>&nbsp;and replace&nbsp;<code>"ccc"</code>&nbsp;by&nbsp;<code>"c3"</code>. Thus the compressed string becomes&nbsp;<code>"a2bc3"</code>.</p>



<p>Notice that in this problem, we are not adding&nbsp;<code>'1'</code>&nbsp;after single characters.</p>



<p>Given a&nbsp;string&nbsp;<code>s</code>&nbsp;and an integer&nbsp;<code>k</code>. You need to delete&nbsp;<strong>at most</strong>&nbsp;<code>k</code>&nbsp;characters from&nbsp;<code>s</code>&nbsp;such that the run-length encoded version of&nbsp;<code>s</code>&nbsp;has minimum length.</p>



<p>Find the&nbsp;<em>minimum length of the run-length encoded&nbsp;version of&nbsp;</em><code>s</code><em>&nbsp;after deleting at most&nbsp;</em><code>k</code><em>&nbsp;characters</em>.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> s = "aaabcccd", k = 2
<strong>Output:</strong> 4
<strong>Explanation: </strong>Compressing s without deleting anything will give us "a3bc3d" of length 6. Deleting any of the characters 'a' or 'c' would at most decrease the length of the compressed string to 5, for instance delete 2 'a' then we will have s = "abcccd" which compressed is abc3d. Therefore, the optimal way is to delete 'b' and 'd', then the compressed version of s will be "a3c3" of length 4.</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> s = "aabbaa", k = 2
<strong>Output:</strong> 2
<strong>Explanation: </strong>If we delete both 'b' characters, the resulting compressed string would be "a4" of length 2.
</pre>



<p><strong>Example 3:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> s = "aaaaaaaaaaa", k = 0
<strong>Output:</strong> 3
<strong>Explanation: </strong>Since k is zero, we cannot delete anything. The compressed string is "a11" of length 3.
</pre>



<p><strong>Constraints:</strong></p>



<ul><li><code>1 &lt;= s.length &lt;= 100</code></li><li><code>0 &lt;= k &lt;= s.length</code></li><li><code>s</code>&nbsp;contains only lowercase English letters.</li></ul>



<h2><strong>Solution 0: Brute Force DFS (TLE)</strong></h2>



<p>Time complexity: O(C(n,k))<br>Space complexity: O(k)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">class Solution {
public:
  int getLengthOfOptimalCompression(string s, int k) {
    const int n = s.length();
    auto encode = [&amp;]() -&gt; int {
      char p = '$';
      int count = 0;
      int len = 0;
      for (char c : s) {
        if (c == '.') continue;
        if (c != p) {
          p = c;
          count = 0;
        }
        ++count;
        if (count &lt;= 2 || count == 10 || count == 100)
          ++len;               
      }
      return len;
    };
    function&lt;int(int, int)&gt; dfs = [&amp;](int start, int k) -&gt; int {
      if (start == n || k == 0) return encode();
      int ans = n;
      for (int i = start; i &lt; n; ++i) {
        char c = s[i];
        s[i] = '.'; // delete
        ans = min(ans, dfs(i + 1, k - 1));
        s[i] = c;
      }
      return ans;
    };
    return dfs(0, k);
  }
};</pre>
</div></div>



<h2><strong>Solution1: DP</strong></h2>



<figure class="wp-block-image size-large"><img width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2020/07/1531-ep347-2.png" alt="" class="wp-image-7175" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2020/07/1531-ep347-2.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2020/07/1531-ep347-2-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2020/07/1531-ep347-2-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></figure>



<p>State: <br>i: the start index of the substring<br>last: last char<br>len: run-length<br>k: # of chars that can be deleted.<br><br>base case:<br>1. k &lt; 0: return inf # invalid <br>2. i &gt;= s.length(): return 0 # done<br></p>



<p>Transition:<br>1. if s[i] == last: return carry + dp(i + 1, last, len + 1, k)</p>



<p>2. if s[i] != last:<br>  return min(1 + dp(i + 1, s[i], 1, k, #  start a new group with s[i]<br>     dp(i + 1, last, len, k -1) # delete / skip s[i], keep it as is.</p>



<p>Time complexity: O(n^3*26)<br>Space complexity: O(n^3*26) </p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">int cache[101][27][101][101];
class Solution {
public:
  int getLengthOfOptimalCompression(string s, int k) {    
    memset(cache, -1, sizeof(cache));
    // Min length of compressioned string of s[i:]    
    // 1. last char is |last|
    // 2. current run-length is len
    // 3. we can delete k chars.
    function&lt;int(int, int, int, int)&gt; dp = 
      [&amp;](int i, int last, int len, int k) {
      if (k &lt; 0) return INT_MAX / 2;
      if (i &gt;= s.length()) return 0;      
      int&amp; ans = cache[i][last][len][k];
      if (ans != -1) return ans;
      if (s[i] - 'a' == last) { 
        // same as the previous char, no need to delete.
        int carry = (len == 1 || len == 9 || len == 99);
        ans = carry + dp(i + 1, last, len + 1, k);
      } else {
        ans = min(1 + dp(i + 1, s[i] - 'a', 1, k),  // keep s[i]
                      dp(i + 1, last, len, k - 1)); // delete s[i]
      }
      return ans;
    };
    return dp(0, 26, 0, k);
  }
};</pre>
</div></div>



<h2><strong>State compression</strong></h2>



<figure class="wp-block-image size-large"><img width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2020/07/1531-ep347-3.png" alt="" class="wp-image-7174" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2020/07/1531-ep347-3.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2020/07/1531-ep347-3-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2020/07/1531-ep347-3-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></figure>



<p>dp[i][k] := min len of s[i:] encoded by deleting at most k charchters.</p>



<p>dp[i][k] = min(dp[i+1][k-1] # delete s[i]<br>encode_len(s[i~j] == s[i]) + dp(j+1, k &#8211; sum(s[i~j])) for j in range(i, n)) # keep</p>



<p>Time complexity: O(n^2*k)<br>Space complexity: O(n*k)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
class Solution {
public:
  int getLengthOfOptimalCompression(string s, int k) {    
    const int n = s.length();
    vector&lt;vector&lt;int&gt;&gt; cache(n, vector&lt;int&gt;(k + 1, -1));
    function&lt;int(int, int)&gt; dp = [&amp;](int i, int k) -&gt; int {
      if (k &lt; 0) return n;
      if (i + k &gt;= n) return 0;
      int&amp; ans = cache[i][k];
      if (ans != -1) return ans;
      ans = dp(i + 1, k - 1); // delete      
      int len = 0;
      int same = 0;
      int diff = 0;
      for (int j = i; j &lt; n &amp;&amp; diff &lt;= k; ++j) {
        if (s[j] == s[i] &amp;&amp; ++same) {
          if (same &lt;= 2 || same == 10 || same == 100) ++len;
        } else {
          ++diff;
        }
        ans = min(ans, len + dp(j + 1, k - diff));
      }
      return ans;
    };
    return dp(0, k);
  }
};</pre>

</div><h2 class="tabtitle">Java</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
class Solution {
  private int[][] dp;
  private char[] s;
  private int n;
  
  public int getLengthOfOptimalCompression(
    String s, int k) {
    this.s = s.toCharArray();
    this.n = s.length();
    this.dp = new int[n][k + 1];
    for (int[] row : dp)
      Arrays.fill(row, -1);
    return dp(0, k);
  }  
  
  private int dp(int i, int k) {
    if (k &lt; 0) return this.n;
    if (i + k &gt;= n) return 0; // done or delete all.    
    int ans = dp[i][k];
    if (ans != -1) return ans;
    ans = dp(i + 1, k - 1); // delete s[i]
    int len = 0;
    int same = 0;    
    int diff = 0;
    for (int j = i; j &lt; n &amp;&amp; diff &lt;= k; ++j) {
      if (s[j] == s[i]) {
        ++same;
        if (same &lt;= 2 || same == 10 || same == 100) ++len;
      } else {
        ++diff;
      }      
      ans = Math.min(ans, len + dp(j + 1, k - diff)); 
    }
    dp[i][k] = ans;
    return ans;
  }
}</pre>

</div><h2 class="tabtitle">Python3</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag"># Author: Huahua
class Solution:
  def getLengthOfOptimalCompression(self, s: str, k: int) -&gt; int:
    n = len(s)
    @functools.lru_cache(maxsize=None)
    def dp(i, k):
      if k &lt; 0: return n
      if i + k &gt;= n: return 0
      ans = dp(i + 1, k - 1)
      l = 0
      same = 0
      for j in range(i, n):
        if s[j] == s[i]:
          same += 1
          if same &lt;= 2 or same == 10 or same == 100:
            l += 1
        diff = j - i + 1 - same
        if diff &lt; 0: break
        ans = min(ans, l + dp(j + 1, k - diff))
      return ans
    return dp(0, k)</pre>
</div></div>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-1531-string-compression-ii/">花花酱 LeetCode 1531. String Compression II</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-1531-string-compression-ii/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱LeetCode 983. Minimum Cost For Tickets</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-983-minimum-cost-for-tickets/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-983-minimum-cost-for-tickets/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 27 Jan 2019 17:18:37 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[cost]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[medium]]></category>
		<category><![CDATA[optimization]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=4699</guid>

					<description><![CDATA[<p>In a country popular for train travel, you&#160;have planned some train travelling one year in advance.&#160; The days of the year that you will travel&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-983-minimum-cost-for-tickets/">花花酱LeetCode 983. Minimum Cost For Tickets</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In a country popular for train travel, you&nbsp;have planned some train travelling one year in advance.&nbsp; The days of the year that you will travel is given as an array&nbsp;<code>days</code>.&nbsp; Each day is an integer from&nbsp;<code>1</code>&nbsp;to&nbsp;<code>365</code>.</p>



<p>Train tickets are sold in 3 different ways:</p>



<ul><li>a 1-day pass is sold for&nbsp;<code>costs[0]</code>&nbsp;dollars;</li><li>a 7-day pass is sold for&nbsp;<code>costs[1]</code>&nbsp;dollars;</li><li>a 30-day pass is sold for&nbsp;<code>costs[2]</code>&nbsp;dollars.</li></ul>



<p>The passes allow that many days of consecutive travel.&nbsp; For example, if we get a 7-day pass on day 2, then we can travel for 7 days: day 2, 3, 4, 5, 6, 7, and 8.</p>



<p>Return the minimum number of dollars you need to travel every day in the given list of&nbsp;<code>days</code>.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted crayon:false"><strong>Input: </strong>days = [1,4,6,7,8,20], costs = [2,7,15]
<strong>Output: </strong>11
<strong>Explanation: </strong>
For example, here is one way to buy passes that lets you travel your travel plan:
On day 1, you bought a 1-day pass for costs[0] = $2, which covered day 1.
On day 3, you bought a 7-day pass for costs[1] = $7, which covered days 3, 4, ..., 9.
On day 20, you bought a 1-day pass for costs[0] = $2, which covered day 20.
In total you spent $11 and covered all the days of your travel.
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted crayon:false"><strong>Input: </strong>days = [1,2,3,4,5,6,7,8,9,10,30,31], costs = [2,7,15]
<strong>Output: </strong>17
<strong>Explanation: </strong>
For example, here is one way to buy passes that lets you travel your travel plan:
On day 1, you bought a 30-day pass for costs[2] = $15 which covered days 1, 2, ..., 30.
On day 31, you bought a 1-day pass for costs[0] = $2 which covered day 31.
In total you spent $17 and covered all the days of your travel.
</pre>



<p><strong>Note:</strong></p>



<ol><li><code>1 &lt;= days.length &lt;= 365</code></li><li><code>1 &lt;= days[i] &lt;= 365</code></li><li><code>days</code>&nbsp;is in strictly increasing order.</li><li><code>costs.length == 3</code></li><li><code>1 &lt;= costs[i] &lt;= 1000</code></li></ol>



<h2>Solution: DP</h2>



<p>dp[i] := min cost to cover the i-th day<br>dp[0] = 0<br>dp[i] = min(dp[i &#8211; 1] + costs[0], dp[i &#8211; 7] + costs[1], dp[i &#8211; 30] + costs[2])</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua, running time: 0 ms
class Solution {
public:
  int mincostTickets(vector&lt;int&gt;&amp; days, vector&lt;int&gt;&amp; costs) {
    vector&lt;int&gt; req(days.back() + 1);
    vector&lt;int&gt; dp(days.back() + 1);
    for (int day : days) req[day] = 1;
    dp[0] = 0;
    for (int i = 1; i &lt; dp.size(); ++i) {
      if (!req[i]) {
        dp[i] = dp[i - 1];
        continue;
      }
      dp[i] = dp[i - 1] + costs[0];
      dp[i] = min(dp[i], dp[max(0, i - 7)] + costs[1]);
      dp[i] = min(dp[i], dp[max(0, i - 30)] + costs[2]);
    }
    return dp.back();
  }
};</pre>

</div><h2 class="tabtitle">Python</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua, running time: 60 ms
class Solution:
  def mincostTickets(self, days: 'List[int]', costs: 'List[int]') -&gt; 'int':
    req = set(days)
    dp = [0] * (days[-1] + 1)    
    for i in range(1, len(dp)):
      if not i in req: 
        dp[i] = dp[i - 1]
        continue
      dp[i] = min(dp[max(0, i - 1)] + costs[0],
                  dp[max(0, i - 7)] + costs[1],
                  dp[max(0, i - 30)] + costs[2])
    return dp[-1]</pre>
</div></div>



<p>               </p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-983-minimum-cost-for-tickets/">花花酱LeetCode 983. Minimum Cost For Tickets</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-983-minimum-cost-for-tickets/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Knapsack Problem 背包问题</title>
		<link>https://zxi.mytechroad.com/blog/sp/knapsack-problem/</link>
					<comments>https://zxi.mytechroad.com/blog/sp/knapsack-problem/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sat, 10 Nov 2018 17:37:14 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[SP]]></category>
		<category><![CDATA[combination]]></category>
		<category><![CDATA[DFS]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[knapsack]]></category>
		<category><![CDATA[optimization]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=4270</guid>

					<description><![CDATA[<p>Videos 上期节目中我们对动态规划做了一个总结，这期节目我们来聊聊背包问题。 背包问题是一个NP-complete的组合优化问题，Search的方法需要O(2^N)时间才能获得最优解。而使用动态规划，我们可以在伪多项式（pseudo-polynomial time）时间内获得最优解。 0-1 Knapsack Problem 0-1背包问题 Problem Given N items, w[i] is the weight of the i-th item and v[i] is value of&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/sp/knapsack-problem/">Knapsack Problem 背包问题</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h1>Videos</h1>
<p><iframe width="500" height="375" src="https://www.youtube.com/embed/CO0r6kcwHUU?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p><iframe width="500" height="375" src="https://www.youtube.com/embed/rM_G4dboKhc?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<h1></h1>
<p>上期节目中我们对动态规划做了一个总结，这期节目我们来聊聊背包问题。</p>
<p>背包问题是一个NP-complete的组合优化问题，Search的方法需要O(2^N)时间才能获得最优解。而使用动态规划，我们可以在<strong>伪多项式（pseudo-polynomial time）</strong>时间内获得最优解。</p>
<h1><strong>0-1 Knapsack Problem 0-1背包问题</strong></h1>
<h2>Problem</h2>
<p><span style="font-weight: 400;">Given N items, w[i] is the weight of the i-th item and v[i] is value of the i-th item. Given a knapsack with capacity W. Maximize the total value. Each item can be use </span><span style="color: #ff0000;"><b>0 or 1 time</b></span><span style="font-weight: 400;">.</span></p>
<p>0-1背包问题的通常定义是：一共有N件物品，第i件物品的重量为w[i]，价值为v[i]。在总重量不超过背包承载上限W的情况下，能够获得的最大价值是多少？每件物品可以使用<strong>0次或者1次</strong>。</p>
<p>例子：</p>
<p>重量 w = [1, 1, 2, 2]</p>
<p>价值 v = [1, 3, 4, 5]</p>
<p>背包承重 W = 4</p>
<p>最大价值为9，可以选第1,2,4件物品，也可以选第3，4件物品；总重量为4，总价值为9。</p>
<p>动态规划的状态转移方程为：</p><pre class="crayon-plain-tag">dp[i][j] = max(dp[i-1][j], dp[i][j-w[i]] + v[i])</pre><p><img class="alignnone wp-image-4295 size-full" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp10-1.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp10-1.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp10-1-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp10-1-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></p>
<p><img class="alignnone size-large wp-image-4276" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp10-2.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp10-2.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp10-2-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp10-2-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></p>
<p><img class="alignnone wp-image-4290 size-full" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp10-3.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp10-3.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp10-3-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp10-3-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></p>
<p><img class="alignnone wp-image-4293 size-full" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp10-4.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp10-4.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp10-4-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp10-4-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></p>
<p><img class="alignnone size-full wp-image-4303" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp11-1.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp11-1.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp11-1-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp11-1-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></p>
<h2><strong>Solutions</strong></h2>
<p><div class="responsive-tabs">
<h2 class="tabtitle">Search</h2>
<div class="tabcontent">
</p><pre class="crayon-plain-tag">def knapsack01DFS(w, v, W):
  def dfs(s, cur_w, cur_v, ans):
    ans[0] = max(ans[0], cur_v)
    if s == N: return
    for i in range(s, N):
      if cur_w + w[i] &lt;= W:
        dfs(i + 1, cur_w + w[i], cur_v + v[i], ans)
  ans = [0]
  dfs(0, 0, 0, ans)
  return ans[0]</pre><p></div><h2 class="tabtitle">DP2</h2>
<div class="tabcontent">
</p><pre class="crayon-plain-tag">def knapsack01(w, v, W):
  dp = [[0] * (W + 1) for _ in range(N+1)]
  for i in range(1, N + 1):
    dp[i] = dp[i-1].clone()
    for j in range(w[i], W + 1):
      dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i - 1]] + v[i - 1])
  return max(dp[N])</pre><p></div><h2 class="tabtitle">DP1/tmp</h2>
<div class="tabcontent">
</p><pre class="crayon-plain-tag">def knapsack01R(w, v, W):
  dp = [0] * (W + 1)
  for i in range(0, N):
    tmp = list(dp)
    for j in range(w[i], W + 1):
      tmp[j] = max(tmp[j], dp[j - w[i]] + v[i])
    dp = tmp
  return max(dp)</pre><p></div><h2 class="tabtitle">DP1/push</h2>
<div class="tabcontent">
</p><pre class="crayon-plain-tag">def knapsack01R2(w, v, W):
  dp = [0] * (W + 1)
  for i in range(0, N):
    for j in range(W, w[i] - 1, -1):
      dp[j] = max(dp[j], dp[j - w[i]] + v[i])
  return max(dp)</pre><p></div><h2 class="tabtitle">DP1/pull</h2>
<div class="tabcontent">
</p><pre class="crayon-plain-tag">def knapsack01R1(w, v, W):
  dp = [0] * (W + 1)
  for i in range(0, N):
    for j in range(W - w[i], -1, -1):
      dp[j + w[i]] = max(dp[j + w[i]], dp[j] + v[i])
  return max(dp)</pre><p></div></div></p>
<p>&nbsp;</p>
<h1><strong>Unbounded Knapsack Problem 完全背包</strong></h1>
<p><strong>完全背包</strong>、<strong>多重背包</strong>是常见的变形。和01背包的区别在于，完全背包每件物品可以使用<strong>无限多次</strong>，而多重背包每件物品最多可以使用<strong>n[i]次</strong>。两个问题都可以转换成01背包问题进行求解。</p>
<p>但是Naive的转换会大大增加时间复杂度：</p>
<p>完全背包：“复制”第i件物品到一共有 W/w[i] 件</p>
<p>多重背包：“复制”第i件物品到一共有 n[i] 件</p>
<p>然后直接调用01背包进行求解。</p>
<p>时间复杂度：</p>
<p>完全背包 O(Σ(W/w[i])*W)</p>
<p>多重背包 O(Σn[i]*W)</p>
<p>不难看出时间复杂度 = O(物品数量*背包承重)</p>
<p>背包承重是给定的，要降低运行时候，只有减少物品数量。但怎样才能减少总的物品数量呢？</p>
<p>这就涉及到二进制思想：任何一个正整数都可以用 (1, 2, 4, &#8230;, 2^K)的组合来表示。例如14 = 2 + 4 + 8。<br />
原本需要放入14件相同的物品，现在只需要放入3件（重量和价值是原物品的2倍，4倍，8倍）。大幅降低了总的物品数量从而降低运行时间。</p>
<p>完全背包：对于第i件物品，我们只需要创建k = log(W/w[i])件虚拟物品即可。</p>
<p>每件虚拟物品的重量和价值为：1*(w[i], v[i]), 2*(w[i], v[i]), &#8230;, 2^k*(w[i], v[i])。</p>
<p>多重背包：对于第i件物品，我们只需要创建k + 1件虚拟物品即可，其中k = log(n[i])。</p>
<p>每件虚拟物品的重量和价值为：1*(w[i], v[i]), 2*(w[i], v[i]), &#8230;, 2^(k-1)*(w[i], v[i]), 以及 (<strong>n[i] &#8211; 2^k &#8211; 1</strong>) * (w[i], v[i])。</p>
<p>例如：n[i] = 14, k = 3, 虚拟物品的倍数为 1, 2, 4 和 7，这4个数组合可以组成1 ~ 14中的任何一个数，并且不会&gt;14，即不超过n[i]。</p>
<p>二进制转换后直接调用01背包即可</p>
<p>时间复杂度：</p>
<p>完全背包 O(Σlog(W/w[i])*W)</p>
<p>多重背包 O(Σlog(n[i])*W)</p>
<p>空间复杂度 O(W)</p>
<p>其实完全背包和多重背包都可以在 O(NW)时间内完成，前者在视频中有讲到，后者属于<strong>超纲内容</strong>，以后有机会再和大家深入分享。</p>
<p><img class="alignnone size-full wp-image-4300" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp11-2.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp11-2.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp11-2-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp11-2-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></p>
<p><img class="alignnone size-full wp-image-4301" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp11-3.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp11-3.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp11-3-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp11-3-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></p>
<h1><strong>Bounded Knapsack Problem 多重背包</strong></h1>
<p><img class="alignnone wp-image-4304 size-full" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp11-4.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp11-4.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp11-4-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/11/sp11-4-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></p>
<p>&nbsp;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/sp/knapsack-problem/">Knapsack Problem 背包问题</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/sp/knapsack-problem/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
