-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
180 lines (103 loc) · 210 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>钱多多の博客</title>
<link href="/atom.xml" rel="self"/>
<link href="https://cybaol.github.io/"/>
<updated>2020-03-21T01:55:55.619Z</updated>
<id>https://cybaol.github.io/</id>
<author>
<name>Kino</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>字符串专题</title>
<link href="https://cybaol.github.io/2020/03/20/String/"/>
<id>https://cybaol.github.io/2020/03/20/String/</id>
<published>2020-03-20T05:44:00.000Z</published>
<updated>2020-03-21T01:55:55.619Z</updated>
<content type="html"><![CDATA[<p>KMP喜提我狗命</p><a id="more"></a><h2 id="字符串hash初步"><a href="#字符串hash初步" class="headerlink" title="字符串hash初步"></a>字符串hash初步</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*字符串hash是指将一个字符串S映射为一个整数,使得该整数可以尽可能唯一地代表字符串S。</span></span><br><span class="line"><span class="comment">例如:假设字符串均由大写字母A-Z构成。A-Z表示0-25,二十六进制,构成的最大整数26^len - 1</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">hashFunc</span><span class="params">(<span class="keyword">char</span> S[], <span class="keyword">int</span> len)</span> </span>{</span><br><span class="line"><span class="keyword">int</span> id = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < len; i++) {</span><br><span class="line">id = id * <span class="number">26</span> + (S[i] - <span class="string">'A'</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> id;</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*同理,如果字符串中出现了小写字母,那么把A-Z视为0-25,而把a-z作为26-51,五十二进制</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">hashFunc</span><span class="params">(<span class="keyword">char</span> S[], <span class="keyword">int</span> len)</span> </span>{</span><br><span class="line"><span class="keyword">int</span> id = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < len; i++) {</span><br><span class="line"><span class="keyword">if</span>(S[i] >= <span class="string">'A'</span> && S[i] <= <span class="string">'Z'</span>) {</span><br><span class="line">id = id * <span class="number">52</span> + (S[i] - <span class="string">'A'</span>);</span><br><span class="line">}<span class="keyword">else</span> <span class="keyword">if</span>(S[i] >= <span class="string">'a'</span> && S[i] <= <span class="string">'z'</span>) {</span><br><span class="line">id = id * <span class="number">52</span> + (S[i] - <span class="string">'a'</span>) + <span class="number">26</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> id;</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*如果出现数字</span></span><br><span class="line"><span class="comment">① 按照瞎写字母的方式,增大进制数至62。</span></span><br><span class="line"><span class="comment">② 如果字符串的末尾是数字,那么把前面英文字母部分转换成整数,再将末尾的数字直接拼接上去。例如"BCD4"</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">hashFunc</span><span class="params">(<span class="keyword">char</span> S[], <span class="keyword">int</span> len)</span> </span>{</span><br><span class="line"><span class="keyword">int</span> id = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < len - <span class="number">1</span>; i++) {</span><br><span class="line">id = id * <span class="number">26</span> + (S[i] - <span class="string">'A'</span>);</span><br><span class="line">}</span><br><span class="line">id = id * <span class="number">10</span> + (S[len - <span class="number">1</span>] - <span class="string">'0'</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//question: 给出N个字符串(由恰好三位大写字母组成),再给出M个查询字符串,问每个查询字符串在N个字符串中出现的次数。</span></span><br></pre></td></tr></table></figure><h2 id="字符串hash进阶"><a href="#字符串hash进阶" class="headerlink" title="字符串hash进阶"></a>字符串hash进阶</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//H[i] = (H[i-1] × p + index(str[i])) % mod</span></span><br><span class="line"><span class="comment">//其中p = 10000019,mod = 1000000007</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//questin: 给出N个只有小写字母的字符串,求其中不同的字符串个数。</span></span><br><span class="line"><span class="comment">//solution: 把每个字符串转化成整数,然后去重。(可以用set和map,但比字符串hash慢一点点)unordered_set呢?</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><string></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> MOD = <span class="number">1000000007</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> P = <span class="number">10000019</span>;</span><br><span class="line"><span class="built_in">vector</span><<span class="keyword">int</span>> ans;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">long</span> <span class="keyword">long</span> <span class="title">hashFunc</span><span class="params">(<span class="built_in">string</span> str)</span> </span>{</span><br><span class="line"><span class="keyword">long</span> <span class="keyword">long</span> H = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i <str.size(); i++) {</span><br><span class="line">H = (H * P + (str[i] - <span class="string">'a'</span>)) % MOD;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> H;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="built_in">string</span> str;</span><br><span class="line"><span class="keyword">while</span>(getline(<span class="built_in">cin</span>, str), str != <span class="string">"#"</span>) {</span><br><span class="line"><span class="keyword">long</span> <span class="keyword">long</span> id = hashFunc(str);</span><br><span class="line">ans.push_back(id);</span><br><span class="line">}</span><br><span class="line">sort(ans.begin(), ans.end());</span><br><span class="line"><span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < ans.size(); i++) {</span><br><span class="line"><span class="keyword">if</span>(i == <span class="number">0</span> || ans[i] != ans[i<span class="number">-1</span>]) {</span><br><span class="line">count++;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="built_in">cout</span> << count << <span class="built_in">endl</span>;</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//question: 输入两个长度均不超过1000的字符串,求他们的最长公共子串的长度。</span></span><br><span class="line"><span class="comment">//solution: 分别对两个字符串的每个子串求出hash值,然后找出两堆子串对应的hash值中相等的那些,便可以找到最大长度。</span></span><br><span class="line"><span class="comment">//T(n) = O(n² + m²)</span></span><br><span class="line"><span class="comment">//变式: 输出最大公共子串本身codeup2432</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//question: 最长回文子串</span></span><br><span class="line"><span class="comment">//solution: 字符串hash + 二分</span></span><br><span class="line"><span class="comment">//T(n) = O(nlogn)</span></span><br></pre></td></tr></table></figure><h2 id="KMP-算法"><a href="#KMP-算法" class="headerlink" title="KMP 算法"></a>KMP 算法</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//KMP算法由Knuth、Morris、Pratt共同发现的。</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//求解next数组:</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">getNext</span><span class="params">(<span class="keyword">char</span> s[], <span class="keyword">int</span> len)</span> </span>{</span><br><span class="line">next[<span class="number">0</span>] = <span class="number">-1</span>;</span><br><span class="line"><span class="keyword">int</span> j = next[<span class="number">0</span>];</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i < len; i++) {</span><br><span class="line"><span class="keyword">while</span>(j != <span class="number">-1</span> && s[i] != s[j + <span class="number">1</span>])</span><br><span class="line">j = next[j];</span><br><span class="line"><span class="keyword">if</span>(s[i] == s[j + <span class="number">1</span>]) j++;</span><br><span class="line">next[i] = j;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/*算法思想:</span></span><br><span class="line"><span class="comment">① 初始化j = -1,表示pattern当前已被匹配的最后位。</span></span><br><span class="line"><span class="comment">② 让i遍历文本串text,对每个i,执行③④来试图匹配text[i]和pattern[j+1]。</span></span><br><span class="line"><span class="comment">③ 不断令j = next[j],直到j回退为-1,或是text[i] == pattern[j+1]成立。</span></span><br><span class="line"><span class="comment">④ 如果text[i] == pattern[j+1],则令j++。如果j达到m-1,说明pattern是text的子串,返回true。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">KMP</span><span class="params">(<span class="keyword">char</span> text[], <span class="keyword">char</span> pattern[])</span> </span>{</span><br><span class="line"><span class="keyword">int</span> n = <span class="built_in">strlen</span>(text), m = <span class="built_in">strlen</span>(pattern);</span><br><span class="line">getNext(pattern, m);</span><br><span class="line"><span class="keyword">int</span> j = <span class="number">-1</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++) {</span><br><span class="line"><span class="keyword">while</span>(j != <span class="number">-1</span> && text[i] != pattern[j + <span class="number">1</span>])</span><br><span class="line">j = next[j];</span><br><span class="line"><span class="keyword">if</span>(text[i] == pattern[j + <span class="number">1</span>]) j++;</span><br><span class="line"><span class="keyword">if</span>(j == m - <span class="number">1</span>) <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//统计模式串pattern出现次数的KMP算法</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">KMP</span><span class="params">(<span class="keyword">char</span> text[], <span class="keyword">char</span> pattern[])</span> </span>{</span><br><span class="line"><span class="keyword">int</span> n = <span class="built_in">strlen</span>(text), m = <span class="built_in">strlen</span>(pattern);</span><br><span class="line">getNext(pattern, m);</span><br><span class="line"><span class="keyword">int</span> j = <span class="number">-1</span>, ans = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++) {</span><br><span class="line"><span class="keyword">while</span>(j != <span class="number">-1</span> && text[i] != pattern[j + <span class="number">1</span>])</span><br><span class="line">j = next[j];</span><br><span class="line"><span class="keyword">if</span>(text[i] == pattern[j + <span class="number">1</span>]) j++;</span><br><span class="line"><span class="keyword">if</span>(j == m - <span class="number">1</span>) {</span><br><span class="line">ans++;</span><br><span class="line">j = next[j];</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> ans;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//优化next数组: nextval[]</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">getNextval</span><span class="params">(<span class="keyword">char</span> s[], <span class="keyword">int</span> len)</span> </span>{</span><br><span class="line"><span class="keyword">int</span> j = <span class="number">-1</span>;</span><br><span class="line">netxval[<span class="number">0</span>] = <span class="number">-1</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i < len; i++) {</span><br><span class="line"><span class="keyword">while</span>(j != <span class="number">-1</span> && s[i] != s[j + <span class="number">1</span>])</span><br><span class="line">j = nextval[j];</span><br><span class="line"><span class="keyword">if</span>(s[i] == s[j + <span class="number">1</span>]) j++;</span><br><span class="line"><span class="keyword">if</span>(j == <span class="number">-1</span> || s[i + <span class="number">1</span>] != s[j + <span class="number">1</span>])</span><br><span class="line">nextval[i] = j;</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">nextval[i] = nextval[j];</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//从有限自动机的角度看待KMP算法</span></span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>KMP喜提我狗命</p>
</summary>
<category term="algorithm" scheme="https://cybaol.github.io/categories/algorithm/"/>
<category term="字符串" scheme="https://cybaol.github.io/tags/%E5%AD%97%E7%AC%A6%E4%B8%B2/"/>
</entry>
<entry>
<title>动态规划专题</title>
<link href="https://cybaol.github.io/2020/03/18/DP/"/>
<id>https://cybaol.github.io/2020/03/18/DP/</id>
<published>2020-03-18T02:07:00.000Z</published>
<updated>2020-03-21T00:44:40.603Z</updated>
<content type="html"><![CDATA[<p>Dynamic Programming</p><a id="more"></a><pre><code>* 动态规划是一种用来解决一类最优化问题的算法思想* 动态规划将一个复杂问题分解成若干子问题,通过综合子问题的最优解来求得原问题最优解* 动态规划会将每个求解过的子问题的解记录下来,这样当下一次碰到同样子问题时,就可以直接使用之前记录的结果,而不是重复计算* 状态的无后效性:当前状态记录了历史信息,一旦当前状态确定,就不会改变,且未来的决策只能在已有的一个或若干个状态的基础上进行, 历史信息只能通过已有的状态去影响未来的决策。* 一个问题必须拥有"重叠子问题"和"最优子结构",才能用动态规划解决。* 重叠子问题:如果一个问题可以被分解为若干个子问题,且这些子问题会重复出现。* 最优子结构:如果一个问题的最优解可以由其子问题的最优解有效地构造出来,那么称为这个问题拥有的最优子结构。 最优子结构保证了动态规划中的原问题的最优解可以由子问题的最优解推导而来。* 分治与动态规划:分治和动态规划都是将问题分解为子问题,然后合并子问题的解得到原问题的解, 但是不同的是,分治法分解出的子问题时不重叠的,因此分治法解决的问题不拥有重叠子结构,而动态规划解决的问题拥有重叠子结构。* 贪心与动态规划:贪心和动态规划都要求原问题必须拥有最优子结构。二者的区别在于, 贪心直接选择一个子问题去求解,会抛弃一些子问题,这种选择的正确性需要用归纳法证明,而动态规划会考虑所有的子问题。* 动态规划的核心是"如何设计状态和状态转移方程"。</code></pre><h2 id="递归法和递推法"><a href="#递归法和递推法" class="headerlink" title="递归法和递推法"></a>递归法和递推法</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">递归写法(记忆化搜索)</span><br><span class="line">斐波那契(Fibonacci)数列</span><br><span class="line"><span class="comment">//T(n) = O(2^n)</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">F</span><span class="params">(<span class="keyword">int</span> n)</span> </span>{</span><br><span class="line"><span class="keyword">if</span>(n == <span class="number">0</span> || n == <span class="number">1</span>) <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">return</span> F(n<span class="number">-1</span>) + F(n<span class="number">-2</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">dp[n]记录F[n]的结果,并用dp[n] = <span class="number">-1</span>表示F[n]当前还没有被计算过。</span><br><span class="line"><span class="comment">//T(n) = O(n)</span></span><br><span class="line"><span class="keyword">int</span> dp[MAXN];</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">F</span><span class="params">(<span class="keyword">int</span> n)</span> </span>{</span><br><span class="line"><span class="keyword">if</span>(n == <span class="number">0</span> || n == <span class="number">1</span>) <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"><span class="keyword">if</span>(dp[n] != <span class="number">-1</span>) <span class="keyword">return</span> dp[n];</span><br><span class="line"><span class="keyword">else</span> {</span><br><span class="line">dp[n] = F(n<span class="number">-1</span>) + F(n<span class="number">-2</span>);</span><br><span class="line"><span class="keyword">return</span> dp[n];</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">递推写法</span><br><span class="line">数塔问题</span><br><span class="line"></span><br><span class="line">令dp[i][j]表示从第i行第j个数字除法的到达最底层的所有路径中能得到的最大和。</span><br><span class="line">则状态转移方程:</span><br><span class="line">dp[i][j] = max{dp[i+<span class="number">1</span>][j],d[i+<span class="number">1</span>][j+<span class="number">1</span>]} + f[i][j]</span><br><span class="line"></span><br><span class="line">#include <cstdio></span><br><span class="line">#include <algorithm></span><br><span class="line">uisng <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">1000</span>;</span><br><span class="line"><span class="keyword">int</span> f[maxn][maxn], dp[maxn][maxn];</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">int</span> n;</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">"%d"</span>, &n);</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i <= n; i++) {</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">1</span>; j <= i j++) {</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">"%d"</span>, &f[i][j]);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="comment">//边界(第n层)</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">1</span>; j <= n; j++) {</span><br><span class="line">dp[n][j] = f[n][j];</span><br><span class="line">}</span><br><span class="line"><span class="comment">//从第n-1层不断往上计算出dp[i][j]</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = n - <span class="number">1</span>; i >= <span class="number">1</span>; i--) {</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">1</span>; j <= i; j++) {</span><br><span class="line">dp[i][j] = max{dp[i+<span class="number">1</span>][j],d[i+<span class="number">1</span>][j+<span class="number">1</span>]} + f[i][j];</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d\n"</span>, dp[<span class="number">1</span>][<span class="number">1</span>]); <span class="comment">//dp[1][1]即为所需要的答案</span></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="最大连续子序列和"><a href="#最大连续子序列和" class="headerlink" title="最大连续子序列和"></a>最大连续子序列和</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">给定一个数字序列A1,A2,···,An,求i,j(<span class="number">1</span>≤i≤j≤n),使得Ai+···+Aj最大,输出这个最大和</span><br><span class="line">样例:<span class="number">-2</span> <span class="number">11</span> <span class="number">-4</span> <span class="number">13</span> <span class="number">-5</span> <span class="number">-2</span></span><br><span class="line">则最大和为<span class="number">20</span>(<span class="number">11</span><span class="number">-4</span>+<span class="number">13</span>)</span><br><span class="line"></span><br><span class="line">步骤<span class="number">1</span>:令状态dp[i]表示以A[i]作为末尾的连续序列的最大和,以样例为例:序列<span class="number">-2</span> <span class="number">11</span> <span class="number">-4</span> <span class="number">13</span> <span class="number">-5</span> <span class="number">-2</span>,下标分别为<span class="number">0</span>,<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,那么</span><br><span class="line">dp[<span class="number">0</span>] = <span class="number">-2</span></span><br><span class="line">dp[<span class="number">1</span>] = <span class="number">11</span></span><br><span class="line">dp[<span class="number">2</span>] = <span class="number">7</span></span><br><span class="line">dp[<span class="number">3</span>] = <span class="number">20</span></span><br><span class="line">dp[<span class="number">4</span>] = <span class="number">15</span></span><br><span class="line">dp[<span class="number">5</span>] = <span class="number">13</span></span><br><span class="line">步骤<span class="number">2</span>:作如下考虑:因为dp[i]要求是必须以A[i]结尾的连续序列,那么只有两种情况:</span><br><span class="line">① 这个最大和的连续序列只有一个元素,即以A[i]开始,以A[i]结尾</span><br><span class="line">② 这个最大和的连续序列有多个元素,即以前面某处A[p]开始(p<i),一直到A[i]结尾</span><br><span class="line">对第一种情况,最大和就是A[i]本身</span><br><span class="line">对第二种情况,最大和是dp[i<span class="number">-1</span>]+A[i],即A[p]+···+A[i<span class="number">-1</span>]+A[i] = dp[i<span class="number">-1</span>]+A[i]</span><br><span class="line">由于只有两种情况,于是得到状态转移方程:</span><br><span class="line">dp[i] = max{A[i], dp[i<span class="number">-1</span>]+A[i]}</span><br><span class="line"></span><br><span class="line"><span class="comment">//T(n) = O(n)</span></span><br><span class="line">#include <cstdio></span><br><span class="line">#include <algorithm></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">10010</span>;</span><br><span class="line"><span class="keyword">int</span> A[maxn], dp[maxn];</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">int</span> n;</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">"%d"</span>, &n);</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++) {</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">"%d"</span>, A + i);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> sum = dp[<span class="number">0</span>] = A[<span class="number">0</span>];</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i < n; i++) {</span><br><span class="line">dp[i] = max(A[i], dp[i<span class="number">-1</span>] + A[i]);</span><br><span class="line">sum = max(sum, dp[i]);</span><br><span class="line">}</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sum);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="最长不下降子序列"><a href="#最长不下降子序列" class="headerlink" title="最长不下降子序列"></a>最长不下降子序列</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">在一个数字序列中,找到一个最长的子序列(可以不连续),使得这个子序列是不下降(非递减)的。</span><br><span class="line">例如,现有序列A={<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">-1</span>,<span class="number">-2</span>,<span class="number">7</span>,<span class="number">9</span>}(下标从<span class="number">1</span>开始),它的最长不下降子序列是{<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">7</span>,<span class="number">9</span>},长度为<span class="number">5</span></span><br><span class="line"></span><br><span class="line">令dp[i]表示以A[i]结尾的最长不下降子序列长度,这样对A[i]来说有两种可能:</span><br><span class="line">① 如果存在A[i]之前的元素A[j](j<i)使得A[j]≤A[i]且dp[j] + <span class="number">1</span> > dp[i](即</span><br><span class="line">把A[i]跟在以A[j]结尾的LIS后面时能比当前以A[i]结尾的LIS长度更长),那么就把A[i]跟在A[j]结尾的LIS后面,</span><br><span class="line">形成一条更长的不下降子序列(令 dp[i] = d[j] + <span class="number">1</span>)</span><br><span class="line">② 如果A[i]之前的元素都比,那么A[i]就只好自己形成一条LIS,但是长度为<span class="number">1</span>,即这个子序列里面只有一个A[i]。</span><br><span class="line">最后以A[i]结尾的LIS长度就是①②中能形成的最大长度</span><br><span class="line">由此可以写出状态转移方程:</span><br><span class="line">dp[i] = max{<span class="number">1</span>, dp[j]+<span class="number">1</span>}</span><br><span class="line"> (j=<span class="number">1</span>,<span class="number">2</span>,···,i<span class="number">-1</span> && A[j]<A[i])</span><br><span class="line"></span><br><span class="line">#include <cstdio></span><br><span class="line">#include <algorithm></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> N = <span class="number">100</span>;</span><br><span class="line"><span class="keyword">int</span> A[N], dp[N];</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">int</span> n;</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">"%d"</span>, &n);</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>;i <= n; i++) {</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">"%d"</span>, A + i);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> ans = <span class="number">-1</span>; <span class="comment">//记录最大的dp[i]</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i <= n; i++) {</span><br><span class="line">dp[i] = <span class="number">1</span>; <span class="comment">//边界初始条件(即先假设每个元素自成一个序列)</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">1</span>; j < i; j++) {</span><br><span class="line"><span class="keyword">if</span>(A[i] >= A[j] && (dp[j] + <span class="number">1</span> > dp[i])) {</span><br><span class="line">dp[i] = dp[j] + <span class="number">1</span>; <span class="comment">//状态转移方程,用以更新dp[i]</span></span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">ans = max(ans, dp[i]);</span><br><span class="line">}</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d"</span>, ans);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="最长公共子序列-LCS"><a href="#最长公共子序列-LCS" class="headerlink" title="最长公共子序列(LCS)"></a>最长公共子序列(LCS)</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">给定两个字符串(或数字序列)A 和 B,求一个字符串,使得这个字符串是A和B的最长公共部分(子序列可以不连续)</span><br><span class="line">样例:字符串<span class="string">"sadstory"</span>和<span class="string">"adminsorry"</span>的最长公共子序列为<span class="string">"adsory"</span>长度为<span class="number">6</span></span><br><span class="line"></span><br><span class="line">令dp[i][j]表示字符串A的i号位和字符串B的j号位之前的LCS长度(下标从<span class="number">1</span>开始),如dp[<span class="number">4</span>][<span class="number">5</span>]表示<span class="string">"sads"</span>与<span class="string">"admin"</span>的LCS长度。那么可以根据A[i]和B[j]的情况,分为两种决策:</span><br><span class="line">① 若A[i] == B[j],则字符串A与字符串B的LCS增加了<span class="number">1</span>位,即有dp[i][j] = dp[i<span class="number">-1</span>][j<span class="number">-1</span>] + <span class="number">1</span>。</span><br><span class="line">② 若A[i] ≠ B[j],则字符串A的i号位和字符串B的j号位之前的LCS无法<span class="number">1</span>延长,因此dp[i][j]将会继承dp[i<span class="number">-1</span>][j]和dp[i][j<span class="number">-1</span>]中的较大值,即有dp[i][j] = max{dp[i<span class="number">-1</span>][j],dp[i]][j<span class="number">-1</span>]}。</span><br><span class="line">由此得到状态转移方程:</span><br><span class="line">dp[i][j] = dp[i<span class="number">-1</span>][j<span class="number">-1</span>], <span class="keyword">if</span> A[i] == B[i]</span><br><span class="line">dp[i][j] = max{dp[i<span class="number">-1</span>][j], dp[i][j<span class="number">-1</span>]}, <span class="keyword">if</span> A[i] ≠ B[i]</span><br><span class="line">边界:dp[i][<span class="number">0</span>] = dp[<span class="number">0</span>][j] = <span class="number">0</span> (<span class="number">0</span>≤i≤n, <span class="number">0</span>≤j≤m)</span><br><span class="line">最终dp[n][m]即为答案</span><br><span class="line"></span><br><span class="line"><span class="comment">//T(n) = O(nm);</span></span><br><span class="line">#include <cstdio></span><br><span class="line">#include <cstring></span><br><span class="line">#include <algorithm></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> N = <span class="number">100</span>;</span><br><span class="line"><span class="keyword">char</span> A[N], B[N];</span><br><span class="line"><span class="keyword">int</span> dp[N][N] = {<span class="number">0</span>};</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">int</span> n;</span><br><span class="line">gets(A + <span class="number">1</span>); gets(B + <span class="number">1</span>);</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">for(int i = 0; i <= strlen(A + 1); i++) {</span></span><br><span class="line"><span class="comment">dp[i][0] = 0;</span></span><br><span class="line"><span class="comment">}</span></span><br><span class="line"><span class="comment">for(int j = 0; j <= strlen(A + 1); j++) {</span></span><br><span class="line"><span class="comment">dp[0][j] = 0;</span></span><br><span class="line"><span class="comment">}</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i <= <span class="built_in">strlen</span>(A + <span class="number">1</span>); i++) {</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">1</span>; j <= <span class="built_in">strlen</span>(B + <span class="number">1</span>); j++) {</span><br><span class="line"><span class="keyword">if</span>(A[i] == B[j]) {</span><br><span class="line">dp[i][j] = dp[i<span class="number">-1</span>][j<span class="number">-1</span>] + <span class="number">1</span>;</span><br><span class="line">}<span class="keyword">else</span> {</span><br><span class="line">dp[i][j] = max(dp[i<span class="number">-1</span>][j], dp[i][j<span class="number">-1</span>]);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d\n"</span>, dp[<span class="built_in">strlen</span>(A + <span class="number">1</span>)][<span class="built_in">strlen</span>(B + <span class="number">1</span>)]);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="最长回文子串"><a href="#最长回文子串" class="headerlink" title="最长回文子串"></a>最长回文子串</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">给出一个字符串s,求S的最长回文子串的长度。</span><br><span class="line">样例:字符串<span class="string">"PATZJUJZTACCBCC"</span>的最长回文子串是<span class="string">"ATZJUJZTA"</span>,长度为<span class="number">9</span>。</span><br><span class="line"></span><br><span class="line">令dp[i][j]表示S[i]至S[j]所表示的子串是否是回文子串,是则为<span class="number">1</span>,不是为<span class="number">0</span>。</span><br><span class="line">这样根据S[i]是否等于S[j],可以把转移情况分为两类:</span><br><span class="line">① 若S[i] == S[j],那么只要S[i+<span class="number">1</span>]至S[j<span class="number">-1</span>]是回文子串,S[i]至S[j]就是回文子串;</span><br><span class="line">如果S[i+<span class="number">1</span>]至S[j<span class="number">-1</span>]不是回文子串。则S[i]至S[j]一定不是回文子串。</span><br><span class="line">② 若S[i] ≠ S[j],那么S[i]至S[j]一定不是回文子串。</span><br><span class="line">由此可以写出状态转移方程:</span><br><span class="line">dp[i][j] = dp[i+<span class="number">1</span>][j<span class="number">-1</span>], <span class="keyword">if</span> S[i] == S[j]</span><br><span class="line">dp[i][j] = <span class="number">0</span>, <span class="keyword">if</span> S[i] ≠ S[j]</span><br><span class="line">边界:dp[i][i] = <span class="number">1</span>, dp[i][i+<span class="number">1</span>] = (S[i] == S[i+!]) ? <span class="number">1</span> : <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//T(n) = O(n²)</span></span><br><span class="line">#include <iostream></span><br><span class="line">#include <cstdio></span><br><span class="line">#include <cstring></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">1010</span>;</span><br><span class="line"><span class="keyword">char</span> S[maxn];</span><br><span class="line"><span class="keyword">int</span> dp[maxn][maxn];</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="built_in">cin</span>.getline(S, maxn);</span><br><span class="line"><span class="keyword">int</span> len = <span class="built_in">strlen</span>(S), ans = <span class="number">-1</span>;</span><br><span class="line"><span class="built_in">memset</span>(dp, <span class="number">0</span>, <span class="keyword">sizeof</span>(dp));</span><br><span class="line"><span class="comment">//边界</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < len; i++) {</span><br><span class="line">dp[i][i] = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">if</span>(i < len - <span class="number">1</span>) {</span><br><span class="line"><span class="keyword">if</span>(S[i] == S[i+<span class="number">1</span>]) {</span><br><span class="line">dp[i][i+<span class="number">1</span>] = <span class="number">1</span>;</span><br><span class="line">ans = <span class="number">2</span>; <span class="comment">//当前最长回文子串长度</span></span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="comment">//状态转移方程</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> L = <span class="number">3</span>; L <= len; L++) {</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i + L <span class="number">-1</span> < len; i++) {</span><br><span class="line"><span class="keyword">int</span> j = i + L - <span class="number">1</span>; <span class="comment">//子串右端点</span></span><br><span class="line"><span class="keyword">if</span>(S[i] == S[j] && dp[i+<span class="number">1</span>][j<span class="number">-1</span>] == <span class="number">1</span>) {</span><br><span class="line">dp[i][j] = <span class="number">1</span>;</span><br><span class="line">ans = L;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d\n"</span>, ans);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">二分+字符串<span class="function">hash <span class="title">T</span><span class="params">(n)</span> </span>= O(nlogn)</span><br><span class="line">Manacher算法 T(n) = O(n)</span><br></pre></td></tr></table></figure><h2 id="DAG最长路"><a href="#DAG最长路" class="headerlink" title="DAG最长路"></a>DAG最长路</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line">解决两个问题</span><br><span class="line">① 求整个DAG中的最长路径(不固定起点和终点)</span><br><span class="line">② 固定终点,求DAG的最长路径</span><br><span class="line"></span><br><span class="line">第一个问题:给定一个有向无环图,怎样求解整个图的所有路径中权值之和最大的那条。</span><br><span class="line">令dp[i]表示从i号顶点除法能获得的最长路径长度,这样所有dp[i]的最大值就是整个DAG的最长路径长度。</span><br><span class="line">如果从i号顶点出发能直接到达顶点j1,j2,···,jk,而dp[j1], dp[j2], ···,dp[jk]均已知,</span><br><span class="line">那么就有dp[i] = max{dp[j] + length[i->j],(i,j)∈E}</span><br><span class="line">根据上面思路可以按照逆拓扑序列的顺序来求解dp数组</span><br><span class="line">所以我选择递归(。・ω・。)</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> DP(<span class="keyword">int</span> i) {</span><br><span class="line"><span class="keyword">if</span>(dp[i] > <span class="number">0</span>) <span class="keyword">return</span> dp[i];</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j < n; j++) {</span><br><span class="line"><span class="keyword">if</span>(G[i][j] != INF) {</span><br><span class="line">dp[i] = max(dp[i], DP[j] + G[i][j]);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> dp[i];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">开一个<span class="keyword">int</span>型choice数组记录最长路径的后继结点,</span><br><span class="line">如果最终有多条路径,将choice数组改为<span class="built_in">vector</span>类型的数组(Dijkstra算法中有多条路径时的做法),记得去实现它哦。</span><br><span class="line">还有如何求解最长路径条数。</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">DP</span><span class="params">(<span class="keyword">int</span> i)</span> </span>{</span><br><span class="line"><span class="keyword">if</span>(dp[i] > <span class="number">0</span>) <span class="keyword">return</span> dp[i];</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j < n; j++) { <span class="comment">//遍历i的所有出边</span></span><br><span class="line"><span class="keyword">if</span>(G[i][j] != INF) {</span><br><span class="line"><span class="keyword">int</span> temp = DP[i] + G[i][j];</span><br><span class="line"><span class="keyword">if</span>(temp > dp[i]) {</span><br><span class="line">dp[i] = temp;</span><br><span class="line">choice[i] = j; <span class="comment">//i号顶点的后继顶点是j</span></span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> dp[i]; <span class="comment">//返回计算完的dp[i]</span></span><br><span class="line">}</span><br><span class="line">调用printPath前需要先得到最大的dp[i],然后将i作为路径起点传入</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">printPath</span><span class="params">(<span class="keyword">int</span> i)</span> </span>{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d"</span>, i);</span><br><span class="line"><span class="keyword">while</span>(choice[i] != <span class="number">-1</span>) { <span class="comment">//choice数组初始化为-1</span></span><br><span class="line">i = choice[i];</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"->%d"</span>, i);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">第二个问题:固定终点,求DAG的最长路径</span><br><span class="line">令dp[i]表示从i号顶点出发到达终点(假设终点为T)能获得的最长路径长度,</span><br><span class="line">同理,如果从i号顶点出发能直接到达顶点j1,j2,···,jk,而dp[j1], dp[j2], ···,dp[jk]均已知,</span><br><span class="line">那么就有dp[i] = max{dp[j] + length[i->j],(i,j)∈E}</span><br><span class="line">边界:dp[T] = <span class="number">0</span>, so problem is coming, 数组不能初始化为<span class="number">0</span>了</span><br><span class="line">合适做法:初始化dp数组为一个负的大数来保证<span class="string">"无法到达终点"</span>的含义得以表达,然后设置一个vis数组表示顶点是否已经被计算。</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> DP(<span class="keyword">int</span> i) {</span><br><span class="line"><span class="keyword">if</span>(vis[i] == <span class="literal">true</span>) <span class="keyword">return</span> dp[i]; <span class="comment">//dp[i]已计算得到直接返回,减少重复计算</span></span><br><span class="line">vis[i] = <span class="literal">true</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j < n; j++) {</span><br><span class="line"><span class="keyword">if</span>(G[i][j] != INF) {</span><br><span class="line">dp[i] = max(dp[i], DP[j] + G[i][j]);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> dp[i];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">经典问题:矩形嵌套问题</span><br></pre></td></tr></table></figure><h2 id="背包问题"><a href="#背包问题" class="headerlink" title="背包问题"></a>背包问题</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">01</span>背包问题:</span><br><span class="line">有n件物品,每件物品的重量为w[i],价值为c[i]。现有一个容量为V的背包,</span><br><span class="line">问如何选取物品放入背包,使得背包内物品的总价值最大。其中每件物品都只有<span class="number">1</span>件。</span><br><span class="line">样例:</span><br><span class="line"><span class="number">5</span> <span class="number">8</span> <span class="comment">// n == 5,v == 8</span></span><br><span class="line"><span class="number">3</span> <span class="number">5</span> <span class="number">1</span> <span class="number">2</span> <span class="number">2</span> <span class="comment">// w[i]</span></span><br><span class="line"><span class="number">4</span> <span class="number">5</span> <span class="number">2</span> <span class="number">1</span> <span class="number">3</span> <span class="comment">// c[i]</span></span><br><span class="line">T(n) = O(nV)</span><br><span class="line"></span><br><span class="line">令dp[i][j]表示前i件物品(<span class="number">1</span> ≤ i ≤ n,<span class="number">0</span> ≤ j ≤ v)恰好装入容量为j的背包中所能获得的最大价值。然后求解dp[i][j]:</span><br><span class="line">考虑对第i件物品的选择策略,有两种:</span><br><span class="line">① 不放第i件物品,那么问题转化为前i<span class="number">-1</span>件物品恰好装入容量为j的背包中所能获得的最大价值。也即dp[i<span class="number">-1</span>][j]。</span><br><span class="line">② 放第i件物品,那么问题转化为前i<span class="number">-1</span>件物品恰好装入容量为j-w[i]的背包中所能获得的最大价值。也即dp[i<span class="number">-1</span>][j-w[i]] + c[i]。</span><br><span class="line">因此状态转移方程为:</span><br><span class="line">dp[i][j] = max{dp[i<span class="number">-1</span>][j], dp[i<span class="number">-1</span>][j-w[i]] + c[i]}</span><br><span class="line">(<span class="number">1</span> ≤ i ≤ n,w[i] ≤ j ≤ v)</span><br><span class="line">边界: dp[<span class="number">0</span>][j] = <span class="number">0</span>(<span class="number">0</span> ≤ j ≤ v)</span><br><span class="line">答案: dp[n][v]</span><br><span class="line">空间复杂度: O(nv)</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i <= n; i++) {</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">1</span>; j <= v; j++) {</span><br><span class="line"><span class="keyword">if</span>(j < w[i]) { <span class="comment">//鲲之大,一包装不下</span></span><br><span class="line">dp[i][j] = dp[i<span class="number">-1</span>][j];</span><br><span class="line">}<span class="keyword">else</span> {</span><br><span class="line">dp[i][j] = max(dp[i<span class="number">-1</span>][j], dp[i<span class="number">-1</span>][j-w[i]] + c[i]);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">优化: 一维: </span><br><span class="line">dp[j] = max{dp[j], dp[j-w[i]] + c[i]}</span><br><span class="line">(<span class="number">1</span> ≤ i ≤ n,w[i] ≤ j ≤ v)</span><br><span class="line">边界: dp[j] = <span class="number">0</span>, <span class="number">0</span> ≤ j ≤ v</span><br><span class="line">答案: dp[v]</span><br><span class="line">空间复杂度: O(v)</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i <= n; i++) {</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> j = v; j >= w[i]; j--) {</span><br><span class="line">dp[j] = max(dp[j], dp[j-w[i]] + c[i]);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">优化版完整代码:</span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">100</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxv = <span class="number">1000</span>;</span><br><span class="line"><span class="keyword">int</span> w[maxn], c[maxn], dp[maxn] = {<span class="number">0</span>};</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">int</span> n, v;</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">"%d%d"</span>, &n, &v);</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++) {</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">"%d"</span>, w + i);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++) {</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">"%d"</span>, c + i);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i <= n; i++) {</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> j = v; j >= w[i]; j--) {</span><br><span class="line">dp[j] = max(dp[j], dp[j-w[i]] + c[i]);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d\n"</span>,dp[v]);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">如果需要知道是哪些物品被放入了背包,可用<span class="string">"回溯算法"</span>(针对未优化版本)</span><br><span class="line">算法思想:</span><br><span class="line">从表的右下角dp[n][v]开始回溯,</span><br><span class="line">如果发现前n个物品最佳组合的价值和前n<span class="number">-1</span>个物品的最佳组合的价值一样,说明第n个物品没有被装入。</span><br><span class="line">否则,第n个物品被装入。</span><br><span class="line">soluton: 增加一个object[], object[i] = <span class="literal">true</span>表示第i个物品被装入, <span class="literal">false</span>表示没装入。</span><br><span class="line"><span class="keyword">bool</span> object[maxn] = {<span class="literal">false</span>};</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Find</span><span class="params">(<span class="keyword">int</span> i, <span class="keyword">int</span> j)</span> </span>{</span><br><span class="line"><span class="keyword">if</span>(i == <span class="number">0</span>) {</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++) {</span><br><span class="line"><span class="keyword">if</span>(i) <span class="built_in">printf</span>(<span class="string">" "</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d"</span>, object[i]);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>(dp[i][j] == dp[i<span class="number">-1</span>][j]) { <span class="comment">//第i个物品没有被装入</span></span><br><span class="line">object[i] = <span class="literal">false</span>;</span><br><span class="line">Find(i<span class="number">-1</span>, j);</span><br><span class="line">}<span class="keyword">else</span> { <span class="comment">//第i个物品被装入</span></span><br><span class="line">object[i] = <span class="literal">true</span>;</span><br><span class="line">Find(i<span class="number">-1</span>,j-w[i]);</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">(<span class="number">1</span>)最大连续子序列和</span><br><span class="line">令dp[i]表示以A[i]作为末尾的连续序列的最大和</span><br><span class="line">(<span class="number">2</span>)最长不下降子序列(LIS)</span><br><span class="line">令dp[i]表示以A[i]结尾的最长不下降子序列长度</span><br><span class="line">(<span class="number">3</span>)最长公共子序列(LCS)</span><br><span class="line">令dp[i][j]表示字符串A的i号位和字符串B的j号位之前的LCS长度</span><br><span class="line">(<span class="number">4</span>)最长回文子串</span><br><span class="line">令dp[i][j]表示S[i]至S[j]所表示的子串是否是回文子串</span><br><span class="line">(<span class="number">5</span>)数塔DP</span><br><span class="line">令dp[i][j]表示从第i行第j个数字除法的到达最底层的所有路径上所能得到的最大和</span><br><span class="line">(<span class="number">6</span>)DAG最长路</span><br><span class="line">令dp[i]表示从i号顶点出发能获得的最长路径长度</span><br><span class="line">(<span class="number">7</span>)<span class="number">01</span>背包</span><br><span class="line">令dp[i][v]表示前i件物品恰好装入容量为v的背包中能获得的最大价值。</span><br><span class="line">(<span class="number">8</span>)完全背包</span><br><span class="line">令dp[i][v]表示前i件物品恰好装入容量为v的背包中能获得的最大价值。</span><br><span class="line"></span><br><span class="line">(<span class="number">1</span>)-(<span class="number">4</span>): </span><br><span class="line">当题目与序列或字符串(记为A)有关时,可以考虑把状态设计成下面两种形式,然后根据端点特点去考虑状态转移方程。</span><br><span class="line">① 令dp[i]表示以A[i]结尾(或开头)的XXX</span><br><span class="line">② 令dp[i][j]表示A[i]至A[j]区间的XXX</span><br><span class="line">其中XXX均为原问题的表述。</span><br><span class="line"></span><br><span class="line">(<span class="number">5</span>)-(<span class="number">8</span>):</span><br><span class="line">状态设计都包含某种<span class="string">"方向"</span>的意思。</span><br><span class="line">分析题目中的状态需要几维来表示,然后对其中的每一维采取下面的某一个表述:</span><br><span class="line">① 恰好为i。</span><br><span class="line">② 前i。</span><br><span class="line">在每一维的含义设置完毕之后,dp数组的含义可以设置成<span class="string">"令dp数组表示恰好为i(或前i)、恰好为j(或前j)······的XXX"</span>,</span><br><span class="line">其中XXX为原问题的描述。接下来通过端点的特点去考虑状态转移方程。</span><br><span class="line"></span><br><span class="line">注:在大多数情况下,都可以把动态规划可解的问题看做一个DAG,图中的结点就是状态,边就是状态转移的方向,</span><br><span class="line">求解问题的顺序就是按照DAG的拓扑序列求解。</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>Dynamic Programming</p>
</summary>
<category term="algorithm" scheme="https://cybaol.github.io/categories/algorithm/"/>
<category term="动态规划" scheme="https://cybaol.github.io/tags/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/"/>
</entry>
<entry>
<title>树算法</title>
<link href="https://cybaol.github.io/2020/03/13/Tree/"/>
<id>https://cybaol.github.io/2020/03/13/Tree/</id>
<published>2020-03-12T23:46:00.000Z</published>
<updated>2020-03-17T15:05:48.023Z</updated>
<content type="html"><![CDATA[<p>早起的虫儿被鸟吃</p><a id="more"></a><pre><code>* 二叉树的存储:链式存储和数组。* 二叉树的遍历:先序、中序、后序、层序。</code></pre><h1 id="二叉树的遍历"><a href="#二叉树的遍历" class="headerlink" title="二叉树的遍历"></a>二叉树的遍历</h1><h2 id="层序遍历"><a href="#层序遍历" class="headerlink" title="层序遍历"></a>层序遍历</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//算法思想:</span></span><br><span class="line"><span class="comment">//①将根节点root加入队列q。</span></span><br><span class="line"><span class="comment">//②取出队首结点,访问之。</span></span><br><span class="line"><span class="comment">//③如果该结点有左孩子,将左孩子入队。</span></span><br><span class="line"><span class="comment">//④如果该结点有有孩子,将有孩子入队。</span></span><br><span class="line"><span class="comment">//⑤返回②,直到队列为空。</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">LayerOrder</span><span class="params">(node* root)</span> </span>{ <span class="comment">//带层次</span></span><br><span class="line"><span class="built_in">queue</span><node*> q;</span><br><span class="line">root->layer = <span class="number">1</span>;</span><br><span class="line">q.push(root);</span><br><span class="line"><span class="keyword">while</span>(!q.empty()){</span><br><span class="line">node* p = q.front();</span><br><span class="line">q.pop();</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d "</span>, p->data);</span><br><span class="line"><span class="keyword">if</span>(p->left != <span class="literal">NULL</span>) {</span><br><span class="line">p->left->layer = p->layer + <span class="number">1</span>;</span><br><span class="line">q.push(p->left);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>(p->right != <span class="literal">NULL</span>) {</span><br><span class="line">p->right->layer = p->layer + <span class="number">1</span>;</span><br><span class="line">q.push(p->right);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="建立二叉树"><a href="#建立二叉树" class="headerlink" title="建立二叉树"></a>建立二叉树</h1><h2 id="已知先序中序"><a href="#已知先序中序" class="headerlink" title="已知先序中序"></a>已知先序中序</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//算法思想:</span></span><br><span class="line"><span class="comment">//①先序数组的第零个结点为根结点。</span></span><br><span class="line"><span class="comment">//②遍历中序数组找出根结点位置并记录。</span></span><br><span class="line"><span class="comment">//③计算中序数组左子树个数</span></span><br><span class="line"><span class="comment">//④递归建立左右子树。</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//其他情况算法类似,重点是确定根结点和数组区间范围。</span></span><br><span class="line"></span><br><span class="line"><span class="function">node* <span class="title">create</span><span class="params">(<span class="keyword">int</span> preL, <span class="keyword">int</span> preR, <span class="keyword">int</span> inL, <span class="keyword">int</span> inR)</span> </span>{</span><br><span class="line"><span class="keyword">if</span>(preL > preR) <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">node* root = <span class="keyword">new</span> node;</span><br><span class="line">root->data = pre[preL];</span><br><span class="line"><span class="keyword">int</span> k = inL;</span><br><span class="line"><span class="keyword">for</span>(; k < inR; k++)</span><br><span class="line"><span class="keyword">if</span>(in[k] == root->data) <span class="keyword">break</span>;</span><br><span class="line"><span class="keyword">int</span> numLeft = k - inL;</span><br><span class="line">root->left = create(preL + <span class="number">1</span>, preL + numLeft, inL, k - <span class="number">1</span>);</span><br><span class="line">root->right = create(preL + numLeft + <span class="number">1</span>, preR, k + <span class="number">1</span>, inR);</span><br><span class="line"><span class="keyword">return</span> root;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="二叉查找树-BST"><a href="#二叉查找树-BST" class="headerlink" title="二叉查找树(BST)"></a>二叉查找树(BST)</h1><pre><code>* 左边小右边大* 对二叉查找树进行"中序"遍历,遍历结果是有序的* 如果给定序列是有序的或者排序后有序,可以中序递归建立BST</code></pre><h2 id="查找操作"><a href="#查找操作" class="headerlink" title="查找操作"></a>查找操作</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">search</span><span class="params">(node* root, <span class="keyword">const</span> <span class="keyword">int</span> x)</span> </span>{</span><br><span class="line"><span class="keyword">if</span>(root == <span class="literal">NULL</span>) {</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"search failed!\n"</span>);</span><br><span class="line"><span class="keyword">return</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>(x == root->data)</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d\n"</span>, root->data);</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(x < root->data)</span><br><span class="line">search(root->left, x);</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">search(root->right, x);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="插入操作"><a href="#插入操作" class="headerlink" title="插入操作"></a>插入操作</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">insert</span><span class="params">(node* &root, <span class="keyword">const</span> <span class="keyword">int</span> x)</span> </span>{</span><br><span class="line"><span class="keyword">if</span>(root == <span class="literal">NULL</span>) { <span class="comment">//插入位置</span></span><br><span class="line">root = <span class="keyword">new</span> node;</span><br><span class="line">root->data = x;</span><br><span class="line">root->left = root->right = <span class="literal">NULL</span>;</span><br><span class="line"><span class="keyword">return</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>(x == root->data) <span class="keyword">return</span>; <span class="comment">//结点已存在 直接返回</span></span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(x < root->data)</span><br><span class="line">insert(root->left, x);</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">insert(root->right, x);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="二叉查找树的建立"><a href="#二叉查找树的建立" class="headerlink" title="二叉查找树的建立"></a>二叉查找树的建立</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">node* <span class="title">create</span><span class="params">(<span class="keyword">int</span> data[])</span> </span>{</span><br><span class="line">node* root = <span class="literal">NULL</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">const</span> <span class="keyword">auto</span> val : data) insert(root, val);</span><br><span class="line"><span class="keyword">return</span> root;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="二叉查找树的删除"><a href="#二叉查找树的删除" class="headerlink" title="二叉查找树的删除"></a>二叉查找树的删除</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//寻找以root为根结点的树中的最大权值结点</span></span><br><span class="line"><span class="function">node* <span class="title">findMAX</span><span class="params">(node* root)</span> </span>{</span><br><span class="line"><span class="keyword">while</span>(root->right != <span class="literal">NULL</span>)</span><br><span class="line">root = root->right;</span><br><span class="line"><span class="keyword">return</span> root;</span><br><span class="line">}</span><br><span class="line"><span class="comment">//寻找以root为根结点的树中的最小权值结点</span></span><br><span class="line"><span class="function">node* <span class="title">findMin</span><span class="params">(node* root)</span> </span>{</span><br><span class="line"><span class="keyword">while</span>(root->left != <span class="literal">NULL</span>)</span><br><span class="line">root = root->left;</span><br><span class="line"><span class="keyword">return</span> root;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//算法思想:</span></span><br><span class="line"><span class="comment">//①如果当前结点root为空,说明不存在权值为给定权值 直接返回。</span></span><br><span class="line"><span class="comment">//②如果当前结点root的权值恰为给定权值x,进入删除处理</span></span><br><span class="line"><span class="comment">//a)如果当前结点root不存在左右孩子,说明叶子结点,直接删除。</span></span><br><span class="line"><span class="comment">//b)如果当前结点root存在左孩子,那么在左子树中寻找结点前驱pre,然//后让pre的数据覆盖root,接着在左子树中删除结点pre。</span></span><br><span class="line"><span class="comment">//c)如果当前结点root存在右孩子,那么在右子树中寻找结点后继next,//然后让next的数据覆盖root,接着在右子树中删除结点next。</span></span><br><span class="line"><span class="comment">//③如果给定的权值x小于当前结点的权值,则在左子树中递归删除权值为x//的结点。</span></span><br><span class="line"><span class="comment">//④如果给定的权值x大于当前结点的权值,则在右子树中递归删除权值为x//的结点。</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">deleteNode</span><span class="params">(node* root, <span class="keyword">int</span> x)</span> </span>{</span><br><span class="line"><span class="keyword">if</span>(root == <span class="literal">NULL</span>) <span class="keyword">return</span>; <span class="comment">//不存在权值为x的结点</span></span><br><span class="line"><span class="keyword">if</span>(x == root->data) {<span class="comment">//找到欲删除结点</span></span><br><span class="line"><span class="comment">//delete(root);</span></span><br><span class="line"><span class="keyword">if</span>(root->left == <span class="literal">NULL</span> && root->right == <span class="literal">NULL</span>)</span><br><span class="line">root = <span class="literal">NULL</span>;</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(root->left != <span class="literal">NULL</span>) {</span><br><span class="line">node* pre = findMAX(root->left, x);</span><br><span class="line">root->data = pre->data;</span><br><span class="line">deleteNode(root->left, pre->data);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> {</span><br><span class="line">node* next = findMin(root->right);</span><br><span class="line">root->data = next->data;</span><br><span class="line">deleteNode(root->right, next->data);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(x < root->data)</span><br><span class="line">deleteNode(root->left, x);</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">deleteNode(root->right, x);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="平衡二叉树-AVL树"><a href="#平衡二叉树-AVL树" class="headerlink" title="平衡二叉树(AVL树)"></a>平衡二叉树(AVL树)</h1><pre><code>* AVL树是一棵二叉查找树* 任意结点的左右子树高度之差(平衡因子)的绝对值不超过1</code></pre><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">node</span> {</span></span><br><span class="line"><span class="keyword">int</span> v, height;</span><br><span class="line">node *left, *right;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">getHeight</span><span class="params">(node* root)</span> </span>{</span><br><span class="line"><span class="keyword">if</span>(root == <span class="literal">NULL</span>) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">return</span> root->height;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">getBalanceFactor</span><span class="params">(node* root)</span> </span>{</span><br><span class="line"><span class="keyword">return</span> getHeight(root->left) - getHeight(root->right);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">updateHeight</span><span class="params">(node* root)</span> </span>{</span><br><span class="line">root->height = max(getHeight(root->left), getHeight(root->right)) + <span class="number">1</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="查找操作-1"><a href="#查找操作-1" class="headerlink" title="查找操作"></a>查找操作</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">search</span><span class="params">(node* root, <span class="keyword">const</span> <span class="keyword">int</span> x)</span> </span>{</span><br><span class="line"><span class="keyword">if</span>(root == <span class="literal">NULL</span>) {</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"search failed!\n"</span>);</span><br><span class="line"><span class="keyword">return</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>(x == root->data)</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d\n"</span>, root->data);</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(x < root->data)</span><br><span class="line">search(root->left, x);</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">search(root->right, x);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="插入操作-1"><a href="#插入操作-1" class="headerlink" title="插入操作"></a>插入操作</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//旋转问题:</span></span><br><span class="line"><span class="comment">//左旋(Left Rotation)算法思想:</span></span><br><span class="line"><span class="comment">//①让B的左子树◆成为A的右子树</span></span><br><span class="line"><span class="comment">//②让A成为B的左子树</span></span><br><span class="line"><span class="comment">//③将根结点设定为结点B</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">L</span><span class="params">(node* &root)</span> </span>{</span><br><span class="line">node* p = root->right;</span><br><span class="line">root->right = p->left;</span><br><span class="line">p->left = root;</span><br><span class="line">updateHeight(root);</span><br><span class="line">updateHeight(p);</span><br><span class="line">root = p;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//右旋(Right Rotation)算法思想:</span></span><br><span class="line"><span class="comment">//①让A的右子树◆成为B的左子树</span></span><br><span class="line"><span class="comment">//②让B成为A的右子树</span></span><br><span class="line"><span class="comment">//③将根结点设定为结点A</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">R</span><span class="params">(node* &root)</span> </span>{</span><br><span class="line">node* p = root->left;</span><br><span class="line">root->left = p->right;</span><br><span class="line">p->right = root;</span><br><span class="line">updateHeight(root);</span><br><span class="line">updateHeight(p);</span><br><span class="line">root = p;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//只要把最靠近插入结点的失衡结点调整到正常,路径上的所有结点就都会正常(可证明)</span></span><br><span class="line"><span class="comment">//分LL型、LR型、RR型、RL型</span></span><br><span class="line"><span class="comment">//LR -> LL | RL -> RR</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">insert</span><span class="params">(node* &root, <span class="keyword">const</span> <span class="keyword">int</span> v)</span> </span>{</span><br><span class="line"><span class="keyword">if</span>(root == <span class="literal">NULL</span>) { <span class="comment">//插入位置</span></span><br><span class="line">root = <span class="keyword">new</span> node;</span><br><span class="line">root->v = v;</span><br><span class="line">root->height = <span class="number">1</span>;</span><br><span class="line">root->left = root->right = <span class="literal">NULL</span>;</span><br><span class="line"><span class="keyword">return</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>(v < root->v) {</span><br><span class="line">insert(root->left, v);</span><br><span class="line">updateHeight(root);</span><br><span class="line"><span class="keyword">if</span>(getBalanceFactor(root) == <span class="number">2</span>) {</span><br><span class="line"><span class="keyword">if</span>(getBalanceFactor(root->left) == <span class="number">1</span>) <span class="comment">//LL型</span></span><br><span class="line">R(root);</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(getBalanceFactor(root->left) == <span class="number">-1</span>) { <span class="comment">//LR型</span></span><br><span class="line">L(root->left);</span><br><span class="line">R(root);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> {</span><br><span class="line">insert(root->right, v);</span><br><span class="line">updateHeight(root);</span><br><span class="line"><span class="keyword">if</span>(getBalanceFactor(root) == <span class="number">-2</span>) {</span><br><span class="line"><span class="keyword">if</span>(getBalanceFactor(root->right) == <span class="number">-1</span>) <span class="comment">//RR型</span></span><br><span class="line">L(root);</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(getBalanceFactor(root->left) == <span class="number">1</span>) { <span class="comment">//RL型</span></span><br><span class="line">R(root->right);</span><br><span class="line">L(root);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="AVL树的建立"><a href="#AVL树的建立" class="headerlink" title="AVL树的建立"></a>AVL树的建立</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">node* <span class="title">create</span><span class="params">(<span class="keyword">int</span> data[])</span> </span>{</span><br><span class="line">node* root = <span class="literal">NULL</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">const</span> <span class="keyword">auto</span> v : data) insert(root, v);</span><br><span class="line"><span class="keyword">return</span> root;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="并查集"><a href="#并查集" class="headerlink" title="并查集"></a>并查集</h1><pre><code>* 合并:合并两个集合* 查找:判断两个元素是否在一个集合* 并查集产生的每一个集合都是一棵树* int father[N]; //并查集数组</code></pre><h2 id="初始化"><a href="#初始化" class="headerlink" title="初始化"></a>初始化</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i <= N; i++)</span><br><span class="line">father[i] = i;</span><br></pre></td></tr></table></figure><h2 id="查找"><a href="#查找" class="headerlink" title="查找"></a>查找</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//iterator</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">findFather</span><span class="params">(<span class="keyword">int</span> x)</span></span>{</span><br><span class="line"><span class="keyword">while</span>(x != father[x]) x = father[x];</span><br><span class="line"><span class="keyword">return</span> x;</span><br><span class="line">}</span><br><span class="line"><span class="comment">//recursion</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">findFather</span><span class="params">(<span class="keyword">int</span> x)</span> </span>{</span><br><span class="line"><span class="keyword">if</span>(x == father[x]) <span class="keyword">return</span> x;</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">return</span> findFather(father[x]);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="合并"><a href="#合并" class="headerlink" title="合并"></a>合并</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Union</span><span class="params">(<span class="keyword">int</span> a, <span class="keyword">int</span> b)</span> </span>{</span><br><span class="line"><span class="keyword">int</span> faA = findFather(a);</span><br><span class="line"><span class="keyword">int</span> faB = findFather(b);</span><br><span class="line"><span class="keyword">if</span>(faA != faB)</span><br><span class="line">father[faA] = faB;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="路径压缩"><a href="#路径压缩" class="headerlink" title="路径压缩"></a>路径压缩</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//算法思想:</span></span><br><span class="line"><span class="comment">//①按原来的写法获得v的根结点root</span></span><br><span class="line"><span class="comment">//②重新从v开始走一遍寻找根结点的过程,把路径上经过的所有结点的父亲//全部改为根结点</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">findFather</span><span class="params">(<span class="keyword">int</span> v)</span> </span>{ <span class="comment">//T(n) = O(1)</span></span><br><span class="line"><span class="keyword">if</span>(v == father[v]) <span class="keyword">return</span> v; <span class="comment">// 找到根结点</span></span><br><span class="line"><span class="keyword">else</span> {</span><br><span class="line"><span class="comment">//让当前结点v的父亲全部改为根结点</span></span><br><span class="line"><span class="keyword">int</span> root = findFather(father[v]);</span><br><span class="line">father[v] = root;</span><br><span class="line"><span class="keyword">return</span> root;</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="堆与堆排序"><a href="#堆与堆排序" class="headerlink" title="堆与堆排序"></a>堆与堆排序</h1><pre><code>* 堆是一个完全二叉树* 大顶堆 和 小顶堆* 堆可以用来实现优先队列* int heap[maxn], n; // n为元素个数</code></pre><h2 id="向下调整"><a href="#向下调整" class="headerlink" title="向下调整"></a>向下调整</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//向下调整 T(n) = O(logn)</span></span><br><span class="line"><span class="comment">//其中low为欲调整的数组下表,high一般为堆的最后一个元素的数组下标</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">downAdjust</span><span class="params">(<span class="keyword">int</span> low, <span class="keyword">int</span> high)</span> </span>{</span><br><span class="line"><span class="keyword">int</span> i = low, j = i * <span class="number">2</span>;</span><br><span class="line"><span class="keyword">while</span>(j <= high) {</span><br><span class="line"><span class="keyword">if</span>(j + <span class="number">1</span> <= high && heap[j+<span class="number">1</span>] > heap[j])</span><br><span class="line">j = j + <span class="number">1</span>;</span><br><span class="line"><span class="keyword">if</span>(heap[j] > heap[i]) {</span><br><span class="line">swap(heap[j], heap[i]);</span><br><span class="line">i = j;</span><br><span class="line">j = i * <span class="number">2</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">break</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="建堆"><a href="#建堆" class="headerlink" title="建堆"></a>建堆</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//从最后一名同学位置开始,从下往上 从右往左</span></span><br><span class="line"><span class="comment">//左轮·D·普拉西多</span></span><br><span class="line"><span class="comment">// T(n) = O(n)</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">createHeap</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = n / <span class="number">2</span>; i >= <span class="number">1</span>; i--) {</span><br><span class="line">downAdjust(i, n);</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="删除堆顶"><a href="#删除堆顶" class="headerlink" title="删除堆顶"></a>删除堆顶</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// T(n) = O(n)</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">deleteTop</span><span class="params">()</span></span>{</span><br><span class="line">heap[<span class="number">1</span>] = heap[n--]; <span class="comment">//用最后一个元素覆盖堆顶元素,并让元素个数减1</span></span><br><span class="line">downAdjust(<span class="number">1</span>,n);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="向上调整"><a href="#向上调整" class="headerlink" title="向上调整"></a>向上调整</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// T(n) = O(logn)</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">upAdjust</span><span class="params">(<span class="keyword">int</span> low, <span class="keyword">int</span> high)</span> </span>{</span><br><span class="line"><span class="keyword">int</span> i = high, j = i / <span class="number">2</span>;</span><br><span class="line"><span class="keyword">while</span>(j >= low){</span><br><span class="line"><span class="keyword">if</span>(heap[i] > heap[j]){</span><br><span class="line">swap(heap[i], heap[j]);</span><br><span class="line">i = j;</span><br><span class="line">j = i / <span class="number">2</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">break</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="堆的插入"><a href="#堆的插入" class="headerlink" title="堆的插入"></a>堆的插入</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">insert</span><span class="params">(node* root, <span class="keyword">int</span> x)</span> </span>{</span><br><span class="line">heap[++n] = x; <span class="comment">// 加入到堆最后一个元素后面,并让元素个数加1</span></span><br><span class="line">upAdjust(<span class="number">1</span>, n);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="堆排序-heap-sort"><a href="#堆排序-heap-sort" class="headerlink" title="堆排序(heap sort)"></a>堆排序(heap sort)</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">heapSort</span><span class="params">()</span> </span>{</span><br><span class="line">createHeap();</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = n; i > <span class="number">1</span>; i--){</span><br><span class="line">swap(heap[<span class="number">1</span>], heap[i]);</span><br><span class="line">downAdjust(<span class="number">1</span>,i - <span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="哈夫曼树"><a href="#哈夫曼树" class="headerlink" title="哈夫曼树"></a>哈夫曼树</h1><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//算法思想:</span></span><br><span class="line"><span class="comment">//反复选择两个最小的元素,合并,直到只剩下一个元素</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><queue></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line">priority_queue<<span class="keyword">long</span> <span class="keyword">long</span>, <span class="built_in">vector</span><<span class="keyword">long</span> <span class="keyword">long</span>>, greater<<span class="keyword">long</span> <span class="keyword">long</span>> > q;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">int</span> n;</span><br><span class="line"><span class="keyword">long</span> <span class="keyword">long</span> temp, x, y, ans = <span class="number">0</span>;</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">"%d"</span>, &n);</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++){</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">"%lld"</span>, &temp);</span><br><span class="line">q.push(temp);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">while</span>(q.size() > <span class="number">1</span>) {</span><br><span class="line">x = q.top();</span><br><span class="line">q.pop();</span><br><span class="line">y = q.top();</span><br><span class="line">q.pop();</span><br><span class="line">q.push(x + y);</span><br><span class="line">ans += x + y;</span><br><span class="line">}</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%lld\n"</span>, ans);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>早起的虫儿被鸟吃</p>
</summary>
<category term="algorithm" scheme="https://cybaol.github.io/categories/algorithm/"/>
<category term="树" scheme="https://cybaol.github.io/tags/%E6%A0%91/"/>
</entry>
<entry>
<title>Be a magical developer</title>
<link href="https://cybaol.github.io/2019/11/19/ambition/"/>
<id>https://cybaol.github.io/2019/11/19/ambition/</id>
<published>2019-11-19T15:15:37.000Z</published>
<updated>2020-03-15T05:16:44.689Z</updated>
<content type="html"><![CDATA[<p>《一百种自杀方法》最后一页写着活下去。</p><a id="more"></a><ul><li><a href="https://www.choupangxia.com/2019/09/26/%E4%B8%96%E7%95%8C%E4%B8%8A%E6%9C%80%E5%A5%BD%E7%9A%84%E5%AD%A6%E4%B9%A0%E6%B3%95%EF%BC%9A%E8%B4%B9%E6%9B%BC%E5%AD%A6%E4%B9%A0%E6%B3%95/" target="_blank" rel="noopener">费曼学习法</a> </li><li>康奈尔笔记 </li><li>数据结构与算法(不C9 无算法 一直都坚信它是程序的灵魂 加油)(<a href="https://www.bilibili.com/video/av7134874" target="_blank" rel="noopener">PKU</a>+<a href="https://www.bilibili.com/video/av49361421" target="_blank" rel="noopener">THU</a>+<a href="https://www.bilibili.com/video/av48922404?p=21" target="_blank" rel="noopener">MIT</a>+算法导论英文第三版) </li><li>计算机组成原理(秃头程序员的进阶感觉可还行)(<a href="https://www.bilibili.com/video/av15123338" target="_blank" rel="noopener">HIT</a>) </li><li>操作系统(听说过bug10吧) (<a href="https://www.bilibili.com/video/av6538245" target="_blank" rel="noopener">PKU</a>) </li><li>计算机网络(学好卖网线)(自顶而下英文原版)</li><li>编译原理(<a href="https://www.bilibili.com/video/av17649289" target="_blank" rel="noopener">HIT</a>)</li><li>嵌入式系统(<a href="https://next.xuetangx.com/" target="_blank" rel="noopener">学堂在线</a>)</li><li>信息论与编码(<a href="https://www.bilibili.com/video/av28661250" target="_blank" rel="noopener">THU</a>+<a href="https://www.bilibili.com/video/av26735580" target="_blank" rel="noopener">西电</a>)</li><li><a href="https://www.bilibili.com/video/av9912938" target="_blank" rel="noopener">ML</a> </li><li>前端 </li><li>数据库 </li><li>健身 </li><li>个人札记 <ol><li>学点经济学</li><li>为竞赛而生 </li><li>多看英文原版书 </li><li>多线程+设计模式 </li><li>多看项目源码 </li><li>脚踏实地的理想主义者,既要有高远的理想也要有脚踏实地的精神 </li><li>他们只是起点比我们高 – 2018-10-3 打卡南京大学鼓楼校区 </li><li>见见有趣的人,读读有趣的书,讲讲有趣的故事。 </li><li>有时候我们会觉得自己后知后觉,那是因为学习的太少,了解的太少,很多问题前人已经总结好了现成的方法和方案,我们却不知道,还在自己探索,当然行动缓慢,后知后觉了。只有站在巨人的肩膀上才能看得更远。 </li><li>2019-10-26打卡东南大学四牌楼校区图书馆 </li><li><a href="https://app.yinxiang.com/shard/s40/nl/24222849/82d590e6-3c3b-4af1-87c2-8964f41501e9/" target="_blank" rel="noopener">C语言笔记</a> </li></ol></li></ul>]]></content>
<summary type="html">
<p>《一百种自杀方法》最后一页写着活下去。</p>
</summary>
<category term="techs" scheme="https://cybaol.github.io/categories/techs/"/>
<category term="成长" scheme="https://cybaol.github.io/tags/%E6%88%90%E9%95%BF/"/>
</entry>
<entry>
<title>大学阅读记录</title>
<link href="https://cybaol.github.io/2019/11/07/book/"/>
<id>https://cybaol.github.io/2019/11/07/book/</id>
<published>2019-11-07T11:32:38.000Z</published>
<updated>2020-03-15T05:43:54.760Z</updated>
<content type="html"><![CDATA[<p><img src="./20191120135008.jpg" alt="一起努力(劝退)"></p><a id="more"></a><h2 id="算法类"><a href="#算法类" class="headerlink" title="算法类"></a>算法类</h2><p>花费我时间最长的东西 不放在第一位都觉得对不起自己. </p><ul><li>Introduction to Algorithms </li><li>大话数据结构 </li><li>算法笔记 </li><li>算法笔记上机训练实战指南 </li><li>数学之美</li><li>算法之美 </li><li>初等数论 </li><li>啊哈算法 </li><li>算法竞赛入门经典(第2版) </li><li>算法竞赛入门经典训练指南 </li><li>大学生程序设计课程与竞赛训练教材-算法设计编程实验 <h2 id="语言类杂书"><a href="#语言类杂书" class="headerlink" title="语言类杂书"></a>语言类杂书</h2>同类书籍看了一堆又一堆 就觉得这几本有点意思(索然无味). </li><li>C Traps and Pitfalls </li><li>Expert C Programming </li><li>C Pointer </li><li>C++ STL </li><li>C++ 11 </li><li>Thinking in C++ </li><li>Effective C++ </li><li>More Effective C++ </li><li>Inside The C++ Object Model </li><li>The C++ Standard Library </li><li>Computer Network A Top-Down Approach <h2 id="Python小爬虫"><a href="#Python小爬虫" class="headerlink" title="Python小爬虫"></a>Python小爬虫</h2>骚不动系列,只看了一本两个晚上93分过期末。。。 </li><li>Python编程: 从入门到实践 <h2 id="硬件之路"><a href="#硬件之路" class="headerlink" title="硬件之路"></a>硬件之路</h2></li><li>Computer System A Programmer’s Perspective </li><li>Computer Organization And Design the hardware/software interface </li><li>Computer Architecture A Quantitative Approach </li><li>ARM Cortex-M0 and Cortex-M0+ Processors </li><li>See MIPS Run</li></ul>]]></content>
<summary type="html">
<p><img src="./20191120135008.jpg" alt="一起努力(劝退)"></p>
</summary>
<category term="books" scheme="https://cybaol.github.io/categories/books/"/>
<category term="阅读" scheme="https://cybaol.github.io/tags/%E9%98%85%E8%AF%BB/"/>
</entry>
<entry>
<title>图论算法</title>
<link href="https://cybaol.github.io/2019/11/01/Graph/"/>
<id>https://cybaol.github.io/2019/11/01/Graph/</id>
<published>2019-11-01T03:00:37.000Z</published>
<updated>2020-03-17T14:59:09.226Z</updated>
<content type="html"><![CDATA[<p>早起的鸟儿有虫吃</p><a id="more"></a><h1 id="图的遍历"><a href="#图的遍历" class="headerlink" title="图的遍历"></a>图的遍历</h1><pre><code>* 有两种存储方式:邻接矩阵和邻接表* 在一些顶点数目比较大(一般顶点个数在1000以上)的情况下,使用邻接表而 不是邻接矩阵来存储图。如果是稀疏图,用邻接表,如果是稠密图,用邻接矩阵。</code></pre><h2 id="深度优先搜索dfs遍历图"><a href="#深度优先搜索dfs遍历图" class="headerlink" title="深度优先搜索dfs遍历图"></a>深度优先搜索dfs遍历图</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//按深度优先的方式访问所有未被访问的结点,在结点被访问过后标记为已访问</span></span><br><span class="line">dfs(u) {</span><br><span class="line"> vis[u] = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">for</span>(从u出发到能到达的所有顶点v)</span><br><span class="line"> <span class="keyword">if</span>(vis[v] == <span class="literal">false</span>)</span><br><span class="line"> dfs(v);</span><br><span class="line">}</span><br><span class="line">dfsTravel(G) {</span><br><span class="line"> <span class="keyword">for</span>(G的所有顶点u)</span><br><span class="line"> <span class="keyword">if</span>(vis[u] == <span class="literal">false</span>)</span><br><span class="line"> dfs(u); <span class="comment">//访问u所在连通块</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//邻接矩阵版 DFS</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> n, G[maxV][maxV];<span class="comment">//n顶点数 maxV最大顶点数</span></span><br><span class="line"><span class="keyword">bool</span> vis[maxV] = {<span class="literal">false</span>};<span class="comment">//记录顶点是否被访问过</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> u, <span class="keyword">int</span> depth)</span> </span>{</span><br><span class="line"> vis[u] = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> v = <span class="number">0</span>; v < n; v++)<span class="comment">//遍历u可以到达的顶点v</span></span><br><span class="line"> <span class="keyword">if</span>(G[u][v] != INF && vis[v] == <span class="literal">false</span>)</span><br><span class="line"> dfs(v, depth + <span class="number">1</span>);<span class="comment">//访问v 深度+1</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">travelDFS</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> u = <span class="number">0</span>; u < n; u++)</span><br><span class="line"> <span class="keyword">if</span>(vis[u] == <span class="literal">false</span>)</span><br><span class="line"> dfs(u, <span class="number">1</span>);<span class="comment">//访问u和u所在的连通块</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//邻接表版 DFS</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">vector</span><<span class="keyword">int</span>> arr[maxn];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> u, <span class="keyword">int</span> depth)</span> </span>{</span><br><span class="line"> vis[u] = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < arr[u].size(); i++){</span><br><span class="line"><span class="keyword">int</span> v = arr[u][i];</span><br><span class="line"><span class="keyword">if</span>(vis[i] == <span class="literal">false</span>)</span><br><span class="line"> dfs(v, depth + <span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dfsTrave</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> u = <span class="number">0</span>; u < n; u++) {</span><br><span class="line"> <span class="keyword">if</span>(vis[u] == <span class="literal">false</span>)</span><br><span class="line"> dfs(u, <span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="广度优先搜索bfs遍历图"><a href="#广度优先搜索bfs遍历图" class="headerlink" title="广度优先搜索bfs遍历图"></a>广度优先搜索bfs遍历图</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//建立一个队列,把初始定点加入队列,然后每次都取出队首元素进行访问,并把该定点 </span></span><br><span class="line"><span class="comment">//除法可以到达的未曾加入过队列(而不是未访问)的顶点全部加入队列,直到队列为空。</span></span><br><span class="line">bfs(u) {</span><br><span class="line"> <span class="built_in">queue</span> q;</span><br><span class="line"> 将u入队</span><br><span class="line"> inq[u] = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">while</span>(q非空) {</span><br><span class="line"> <span class="keyword">for</span>(从u出发到可到达的所有顶点v) {</span><br><span class="line"> <span class="keyword">if</span>(inq[v] == <span class="literal">false</span>)</span><br><span class="line"> 将v入队</span><br><span class="line"> inq[v] = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">bfsTrave(G) {</span><br><span class="line"> <span class="keyword">for</span>(G的所有顶点u) {</span><br><span class="line"> <span class="keyword">if</span>(inq[u] == <span class="literal">false</span>)</span><br><span class="line"> bfs(u);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//邻接矩阵版 BFS</span></span><br><span class="line"><span class="keyword">int</span> n, G[maxV][maxV];<span class="comment">//n顶点数 maxV最大顶点数</span></span><br><span class="line"><span class="keyword">bool</span> inq[maxV] = {<span class="literal">false</span>};<span class="comment">//记录顶点的是否入队</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">bfs</span><span class="params">(<span class="keyword">int</span> u)</span> </span>{<span class="comment">//u顶点编号</span></span><br><span class="line"><span class="built_in">queue</span><<span class="keyword">int</span>> q;</span><br><span class="line">q.push(u);<span class="comment">//入队</span></span><br><span class="line">inq[u] = <span class="literal">true</span>;</span><br><span class="line"><span class="keyword">while</span>(!q.empty()) {</span><br><span class="line"><span class="keyword">int</span> u = q.front();</span><br><span class="line">q.pop();</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> v = <span class="number">0</span>; v < n; v++)<span class="comment">//遍历u所在连通块(未入队)并入队</span></span><br><span class="line"><span class="keyword">if</span>(G[u][v] != INF && inq[v] == <span class="literal">false</span>){</span><br><span class="line">q.push(v);、</span><br><span class="line">inq[v] = <span class="literal">true</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/*邻接表:</span></span><br><span class="line"><span class="comment">for(int i = 0; i < arr[u].size(); i++) {</span></span><br><span class="line"><span class="comment"> int v= arr[u][i];</span></span><br><span class="line"><span class="comment"> if(inq[v] == false) {</span></span><br><span class="line"><span class="comment"> q.push(v);</span></span><br><span class="line"><span class="comment"> inq[v] = true;</span></span><br><span class="line"><span class="comment"> }</span></span><br><span class="line"><span class="comment">}</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">travelBFS</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> v = <span class="number">0</span>; v < n; v++)</span><br><span class="line"><span class="keyword">if</span> (inq[v] == <span class="literal">false</span>)</span><br><span class="line">bfs(v);<span class="comment">//遍历v及其所在连通块</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//带层数的 邻接表</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">node</span> {</span></span><br><span class="line"> <span class="keyword">int</span> v;<span class="comment">//顶点编号</span></span><br><span class="line"> <span class="keyword">int</span> layer;<span class="comment">//顶点层号</span></span><br><span class="line">};</span><br><span class="line">next.layer = curNode.layer + <span class="number">1</span>;</span><br><span class="line"><span class="comment">//邻接表中的类型是node,而不是int</span></span><br><span class="line"><span class="built_in">vector</span><node> Adj[N];</span><br></pre></td></tr></table></figure><h1 id="最短路径"><a href="#最短路径" class="headerlink" title="最短路径"></a>最短路径</h1><pre><code>* 单源最短路径:计算源点到其他各顶点的最短路径的长度* 全局最短路径:图中任意两点的最短路径* Dijkstra、Bellman-Ford、SPFA求单源最短路径* Floyd-Warshall可以求全局最短路径,但是效率比较低* SPFA算法是Bellman-Ford算法的队列优化* Dijkstra算法不能求带负权边的最短路径,而SPFA算法、Bellman-Ford算法、Floyd-Warshall可以求带负权边的最短路径* Bellman-Ford算法的核心代码只有4行,Floyd-Warshall算法的核心代码只有5行* 深度优先遍历可以求一个点到另一个点的最短路径的长度</code></pre><h2 id="单源最短路径"><a href="#单源最短路径" class="headerlink" title="单源最短路径"></a>单源最短路径</h2><pre><code>思想来源:图的广度优先遍历bfs</code></pre><h3 id="Dijkstra-算法"><a href="#Dijkstra-算法" class="headerlink" title="Dijkstra 算法"></a>Dijkstra 算法</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Dijkstra 算法:</span></span><br><span class="line"><span class="comment">//对图G(V,E)设置集合S,存放已被访问的顶点,</span></span><br><span class="line"><span class="comment">//然后每次从集合V-S中选择与起点s的最短距离最小的一个顶点(记为u),访问并加入集合S,</span></span><br><span class="line"><span class="comment">//之后,令顶点u为中介点,优化起点s与所有从u能到达的顶点v的最短距离,</span></span><br><span class="line"><span class="comment">//这样的操作执行n次,直到集合S已包含所有顶点。</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> G[maxSize][maxSize], n;</span><br><span class="line"><span class="keyword">int</span> d[maxSize];</span><br><span class="line"><span class="keyword">int</span> pre[maxSize];</span><br><span class="line"><span class="keyword">bool</span> vis[maxSize] = {<span class="literal">false</span>};</span><br><span class="line"><span class="comment">//邻接矩阵</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Dijkstra</span><span class="params">(<span class="keyword">int</span> s)</span> </span>{ <span class="comment">//T(n) = O(V^2)</span></span><br><span class="line">fill(d, d + maxSize, INF);</span><br><span class="line">d[s] = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++){</span><br><span class="line"><span class="keyword">int</span> u = <span class="number">-1</span>, min = INF;<span class="comment">//u 保存最短路径顶点,min保存最短距离</span></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j < n; j++)</span><br><span class="line"><span class="keyword">if</span>(vis[j] == <span class="literal">false</span> && d[j] < min) {</span><br><span class="line">u = j;</span><br><span class="line">min = d[j];</span><br><span class="line">}</span><br><span class="line"><span class="comment">//找不到小于INF的d[u],说明剩下的顶点与起点s不连通</span></span><br><span class="line"><span class="keyword">if</span>(u == <span class="number">-1</span>) <span class="keyword">return</span>;</span><br><span class="line">vis[u] = <span class="literal">true</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> v = <span class="number">0</span>; v < n; v++) {</span><br><span class="line"><span class="comment">//以u为中介点使可以使d[v]更优</span></span><br><span class="line"><span class="keyword">if</span>(G[u][v] != INF && vis[v] == <span class="literal">false</span> && d[u] + G[u][v] < d[v]) {</span><br><span class="line">d[v] = d[u] + G[u][v];</span><br><span class="line">pre[v] = u; <span class="comment">//记录v的前驱结点u</span></span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//邻接表</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Node</span> {</span></span><br><span class="line"><span class="keyword">int</span> v, dis; <span class="comment">//v为边的目标顶点,dis为边权</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="built_in">vector</span><Node> Adj[MAXV];</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j < Adj[u].size(); j++) {</span><br><span class="line"><span class="keyword">int</span> v = Adj[u][j].v; <span class="comment">//通过邻接表直接获得u能到达的顶点v</span></span><br><span class="line"><span class="keyword">if</span>(vis[v] == <span class="literal">false</span> && d[u] + Adj[u][v].dis < d[v]) {</span><br><span class="line">d[v] = d[u] + Adj[u][v].dis;</span><br><span class="line">} </span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//无向图解决方案: 把无向边当成指向相反的有向边</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">DFS</span><span class="params">(<span class="keyword">int</span> s, <span class="keyword">int</span> v)</span> </span>{<span class="comment">//s起点编号,v是当前访问的顶点编号(从终点开始递归)</span></span><br><span class="line"><span class="keyword">if</span>(v == s) { <span class="comment">//如果当前已经打扫起点s,则输出起点并返回</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d\n"</span>, s);</span><br><span class="line"><span class="keyword">return</span>;</span><br><span class="line">}</span><br><span class="line">DFS(s, pre[v]); <span class="comment">//递归访问v的前驱结点pre[v]</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d\n"</span>, v);<span class="comment">//从最深处return回来之后,输出每一层的顶点号</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><pre><code>附加考法:第一标尺是距离,第二标尺常见有三种①新增边权:给每条边再增加一个边权(比如花费),然后要求在最短路径有多条时要求路径上的花费之和最小(如果边权是其它含义,也可以是最大)。</code></pre><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//c[] 从起点s到达顶点u的最少花费c[u]</span></span><br><span class="line"><span class="comment">//cost[u][v]表示u->v的花费</span></span><br><span class="line"><span class="comment">//初始化时只有c[s] = 0 其余均为INF</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> v = <span class="number">0</span>; v < n; v++) {</span><br><span class="line"><span class="keyword">if</span>(G[u][v] != INF && vis[v] == <span class="literal">false</span>) {</span><br><span class="line"><span class="keyword">if</span>(d[u] + G[u][v] < d[v]) {</span><br><span class="line">d[v] = d[u] + G[u][v];</span><br><span class="line">c[v] = c[u] +cost[u][v];</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(d[u] + G[u][v] == d[v] && c[u] +cost[u][v] < c[v]){</span><br><span class="line">c[v] = c[u] +cost[u][v];<span class="comment">//最短距离相同时,看c[v]能否更优</span></span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><pre><code>②新增点权:给每个点增加一个点权(例如每个城市能收集到的物资),然后在最短路径有多条时要求路径上的点权之和最大(如果点权是其它含义也可以是最小)。</code></pre><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//w[]从起点s到顶点u能收集的最大物资w[u]</span></span><br><span class="line"><span class="comment">//weight[u]表示城市u中的物资数目</span></span><br><span class="line"><span class="comment">//初始化时只有w[s]为weight[s] 其余均为0</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> v = <span class="number">0</span>; v < n; v++) {</span><br><span class="line"><span class="keyword">if</span>(G[u][v] != INF && vis[v] == <span class="literal">false</span>) {</span><br><span class="line"><span class="keyword">if</span>(d[u] + G[u][v] < d[v]) {</span><br><span class="line">d[v] = d[u] + G[u][v];</span><br><span class="line">w[v] = w[u] + weight[v];</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(d[u] + G[u][v] == d[v] && w[u] + weight[v] > w[v]){</span><br><span class="line">w[v] = w[u] + weight[v];</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><pre><code>③直接问有多少条最短路径</code></pre><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//num[]从起点s到达顶点u的最短路径条数为num[u]</span></span><br><span class="line"><span class="comment">//初始化只有num[s] = 1 其余均为0</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> v = <span class="number">0</span>; v < n; v++) {</span><br><span class="line"><span class="keyword">if</span>(G[u][v] != INF && vis[v] == <span class="literal">false</span>) {</span><br><span class="line"><span class="keyword">if</span>(d[u] + G[u][v] < d[v]) {</span><br><span class="line">d[v] = d[u] + G[u][v];</span><br><span class="line">num[v] = num[u];</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(d[u] + G[u][v] == d[v]){</span><br><span class="line">num[v] += num[u];<span class="comment">//最短距离相同时累加num</span></span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="Bellman-Ford-算法"><a href="#Bellman-Ford-算法" class="headerlink" title="Bellman-Ford 算法"></a>Bellman-Ford 算法</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 零环、正环、负环</span></span><br><span class="line"><span class="comment">//零环和正环不会影响最短路径求解(因为不能使最短路径更短)</span></span><br><span class="line"><span class="comment">//负环 从源点可以到达,会影响最短路径求解(无法从源点除法到达 不会影响)</span></span><br><span class="line"><span class="comment">//算法思想:</span></span><br><span class="line"><span class="comment">//需要对图中的边进行V - 1轮操作,每轮都遍历图中的所有边:对每条边u->v, </span></span><br><span class="line"><span class="comment">//如果以u为中介点可以使d[v]更小,即d[u] + length[u->v] < d[v]成立时,</span></span><br><span class="line"><span class="comment">//就用d[u] + length[u->v] 更新d[v]。</span></span><br><span class="line"><span class="comment">//T(n) = O(VE)</span></span><br><span class="line"><span class="comment">//第k轮得到从0号顶点"最多通过k条边到达其余各顶点的最短路径长度"</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Node</span> {</span></span><br><span class="line"><span class="keyword">int</span> v, dis; <span class="comment">//v为邻接边的目标顶点, dis为邻接边的边权</span></span><br><span class="line">};</span><br><span class="line"><span class="built_in">vector</span><Node> Adj[MAXV]; <span class="comment">//邻接表</span></span><br><span class="line"><span class="keyword">int</span> n, d[MAXV]; <span class="comment">//n顶点数,d[]用来存放从源点s到达各个顶点的最短距离</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">Bellman</span><span class="params">(<span class="keyword">int</span> s)</span> </span>{</span><br><span class="line">fill(s, d + MAXV, INF);</span><br><span class="line">d[s] = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < n - <span class="number">1</span>; i++) {</span><br><span class="line"><span class="keyword">for</span>(u = <span class="number">0</span>; u < n; u++){<span class="comment">//遍历所有边</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j < Adj[u].size(); j++) {</span><br><span class="line"><span class="keyword">int</span> v = Adj[u][j].v;</span><br><span class="line"><span class="keyword">int</span> dis = Adj[u][j].dis;</span><br><span class="line"><span class="keyword">if</span>(d[u] + dis < d[v]) {</span><br><span class="line">d[v] = d[u] + dis; <span class="comment">//松弛操作</span></span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="comment">//判断负环代码</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> u = <span class="number">0</span>; u < n; u++) {</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j < Adj[u].size(); j++) {</span><br><span class="line"><span class="keyword">int</span> v = Adj[u][j].v;</span><br><span class="line"><span class="keyword">int</span> dis = Adj[u][j].dis;</span><br><span class="line"><span class="keyword">if</span>(d[u] + dis < d[v]) {</span><br><span class="line"><span class="keyword">return</span> <span class="literal">false</span>; <span class="comment">//说明图中有从源点可达的负环</span></span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> <span class="literal">true</span>; <span class="comment">//数组d的所有值都已经达到最优</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="SPFA-算法"><a href="#SPFA-算法" class="headerlink" title="SPFA 算法"></a>SPFA 算法</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Shortest Path Faster Algorithm</span></span><br><span class="line"><span class="comment">//T(n) = O(kE) , k <= 2</span></span><br><span class="line"><span class="comment">//理解SPFA的关键是理解它是如何从Bellman-Ford算法优化得来的</span></span><br><span class="line"><span class="built_in">queue</span><<span class="keyword">int</span>> q;</span><br><span class="line">源点s入队</span><br><span class="line"><span class="keyword">while</span>(队列非空) {</span><br><span class="line">取出队首元素</span><br><span class="line"><span class="keyword">for</span>(u的所有邻接边u->v) {</span><br><span class="line"><span class="keyword">if</span>(d[u] + dis < d[v]) {</span><br><span class="line">d[v] = d[u] + dis;</span><br><span class="line"><span class="keyword">if</span>(v当前不在队列) {</span><br><span class="line">v入队;</span><br><span class="line"><span class="keyword">if</span>(v入队次数大于n - <span class="number">1</span>) {</span><br><span class="line">说明有可达负环,<span class="keyword">return</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="全源最短路径"><a href="#全源最短路径" class="headerlink" title="全源最短路径"></a>全源最短路径</h2><h3 id="Floyd-算法"><a href="#Floyd-算法" class="headerlink" title="Floyd 算法"></a>Floyd 算法</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Floyd算法</span></span><br><span class="line">枚举顶点 k ∈ [<span class="number">1</span>,n]</span><br><span class="line">以顶点 k 作为中介点,枚举所有顶点对i和j (i,j∈ [<span class="number">1</span>,n])</span><br><span class="line">如果dis[i][k] + dis[k][j] < dis[i][j]成立</span><br><span class="line">赋值dis[i][j] = dis[i][k] + dis[k][j]</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> n, m; <span class="comment">//n顶点数, m为边数</span></span><br><span class="line"><span class="keyword">int</span> dis[MAXV][MAXV]; <span class="comment">//dis[i][j]表示顶点i和j的最短距离</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Floyd</span><span class="params">()</span></span>{</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> k = <span class="number">0</span>; k < n; k++) {</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++) {</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j < n; j++) {</span><br><span class="line"><span class="keyword">if</span>(dis[i][k] != INF && dis[k][j] != INF && dis[i][k] + dis[k][j] < dis[i][j])</span><br><span class="line">dis[i][j] = dis[i][k] + dis[k][j];</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="最小生成树"><a href="#最小生成树" class="headerlink" title="最小生成树"></a>最小生成树</h1><pre><code>* 如果是稠密图(边多) prim算法* 如果是稀疏图(边少) kruskal算法</code></pre><h2 id="prim-算法"><a href="#prim-算法" class="headerlink" title="prim 算法"></a>prim 算法</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//prim算法:</span></span><br><span class="line"><span class="comment">//对图G(V,E)设置集合S,存放已被访问的顶点,</span></span><br><span class="line"><span class="comment">//然后每次从集合V-S中选择与集合S的最短距离最小的一个顶点(记为u)访问并加入集合S。</span></span><br><span class="line"><span class="comment">//之后,令顶点u为中介点,优化所有从u能到达的顶点v与集合S之间的最短距离。</span></span><br><span class="line"><span class="comment">//这样执行操作n次(n为顶点个数),直到集合S已包含所有顶点。</span></span><br><span class="line"><span class="comment">//prim算法和Dijkstra算法只有优化d[v]部分不同</span></span><br><span class="line"><span class="comment">//prim算法和Dijkstra算法思路完全相同,只不过是数组d[]含义不同</span></span><br><span class="line">Prim(G, d[]){</span><br><span class="line">初始化</span><br><span class="line"><span class="keyword">for</span>(循环n次){</span><br><span class="line">u = 使d[u]最小的还未被访问的顶点的标号</span><br><span class="line"><span class="keyword">for</span>(从u除法能到达的所有顶点){</span><br><span class="line"><span class="keyword">if</span>(v未被访问&& 以u为中介点使得v与集合S的最短距离d[v]更优){</span><br><span class="line">将G[u][v]赋值给v与集合S的最短距离d[v]</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//邻接矩阵</span></span><br><span class="line"><span class="keyword">int</span> n, G[MAXV][MAXV]; <span class="comment">//n为顶点数</span></span><br><span class="line"><span class="keyword">int</span> d[MAXV]; <span class="comment">//顶点与集合S的最短距离</span></span><br><span class="line"><span class="keyword">bool</span> vis[MAXV] = {<span class="literal">false</span>}; <span class="comment">//标记数组,vis[i] == true表示已访问。初值均为false</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">prim</span><span class="params">()</span></span>{<span class="comment">//默认0号为初始点</span></span><br><span class="line">fill(d, d + MAXV, INF);</span><br><span class="line">d[<span class="number">0</span>] = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">int</span> ans = <span class="number">0</span>; <span class="comment">//存放最小生成树的边权之和</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++) {</span><br><span class="line"><span class="keyword">int</span> u = <span class="number">-1</span>, min = INF; <span class="comment">//u使d[u]最小,min存放该最小的d[u]</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j < n; j++) {</span><br><span class="line"><span class="keyword">if</span>(vis[j] == <span class="literal">false</span> && d[j] < min) {</span><br><span class="line">u = j;</span><br><span class="line">min = d[j];</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="comment">//找不到小于INF的d[u],则剩下的顶点和集合S不连通</span></span><br><span class="line"><span class="keyword">if</span>(u == <span class="number">-1</span>) <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">vis[u] = <span class="literal">true</span>;</span><br><span class="line">ans += d[u];</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> v = <span class="number">0</span>; v < n; v++) {</span><br><span class="line"><span class="keyword">if</span>(G[u][v] != INF && vis[v] ==<span class="literal">false</span> && G[u][v] < d[v]){</span><br><span class="line">d[v] = G[u][v];</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> ans;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//邻接表</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Node</span> {</span></span><br><span class="line"><span class="keyword">int</span> v, dis; <span class="comment">//v为边的目标顶点,dis为边权</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="built_in">vector</span><Node> Adj[MAXV]</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j < Adj[u].size(); j++) {</span><br><span class="line"><span class="keyword">int</span> v = Adj[u][j].v; <span class="comment">//通过邻接表直接获得u能到达的顶点v</span></span><br><span class="line"><span class="keyword">if</span>(vis[v] == <span class="literal">false</span> && Adj[u][j].dis < d[v]) {</span><br><span class="line">d[v] = Adj[u][v].dis;</span><br><span class="line">} </span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="kruskal-算法"><a href="#kruskal-算法" class="headerlink" title="kruskal 算法"></a>kruskal 算法</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//kruskal算法采用"边贪心"策略,步骤:</span></span><br><span class="line"><span class="comment">//①对所有边按边权从小到大进行排序。</span></span><br><span class="line"><span class="comment">//②按边权从小到大测试所有边,如果当前测试所连接的两个顶点不在同一//个连通块中,</span></span><br><span class="line"><span class="comment">//则把这条测试边加入当前最小生成树中;否则,将边舍弃</span></span><br><span class="line"><span class="comment">//③执行步骤②,直到最小生成树中的边数等于总顶点数-1或是测试完所有边//时结束。</span></span><br><span class="line"><span class="comment">//而当结束时如果最小生成树的边数小于总顶点数-1,说明该图不连通</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">edge</span> {</span></span><br><span class="line"><span class="keyword">int</span> u, v;<span class="comment">//边的两个端点编号</span></span><br><span class="line"><span class="keyword">int</span> cost;<span class="comment">//边权</span></span><br><span class="line">}E[MAXE];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">kruskal</span><span class="params">()</span></span>{</span><br><span class="line">令最小生成树的边权之和为ans,最小生成树的当前边数为Num_Edge;</span><br><span class="line">将所有边按边权从小到大排序;</span><br><span class="line"><span class="keyword">for</span>(从小到大枚举所有边){</span><br><span class="line"><span class="keyword">if</span>(当前测试边的两个端点在不同的连通块中) {</span><br><span class="line">将该测试边加入最小生成树中;</span><br><span class="line">ans += 测试边边权;</span><br><span class="line">最小生成树的当前边数Num_Edge 加 <span class="number">1</span>;</span><br><span class="line">当边数Num_Edge等于顶点数减<span class="number">1</span>时结束循环;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> ans;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> father[N];<span class="comment">//并查集数组</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">findFather</span><span class="params">(<span class="keyword">int</span> x)</span></span>{</span><br><span class="line"><span class="keyword">while</span>(x != father[x]) x = father[x];</span><br><span class="line"><span class="keyword">return</span> x;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">cmp</span><span class="params">(edge a, edge b)</span> </span>{</span><br><span class="line"><span class="keyword">return</span> a.cost < b.cost;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">kruskal</span><span class="params">(<span class="keyword">int</span> n, <span class="keyword">int</span> m)</span></span>{ <span class="comment">//n顶点数 m边数</span></span><br><span class="line"><span class="keyword">int</span> ans = <span class="number">0</span>,Num_Edge = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i <= n; i++) {</span><br><span class="line">father[i] = i;</span><br><span class="line">}</span><br><span class="line">sort(E, E + m, cmp); <span class="comment">//所有边按边权从小到大排序</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < m; i++) { <span class="comment">//枚举所有边</span></span><br><span class="line"><span class="keyword">int</span> faU = findFather(E[i].u);</span><br><span class="line"><span class="keyword">int</span> faV = findFather(E[i].v);</span><br><span class="line"><span class="keyword">if</span>(faU != faV) { <span class="comment">//如果不在一个集合中</span></span><br><span class="line">father[faU] = faV;</span><br><span class="line">ans += E[i].cost;</span><br><span class="line">Num_Edge++;</span><br><span class="line"><span class="keyword">if</span>(Num_Edge == n - <span class="number">1</span>) <span class="keyword">break</span>;<span class="comment">//边数等于顶点数减1时结束算法</span></span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>(Num_Edge != n - <span class="number">1</span>) <span class="keyword">return</span> <span class="number">-1</span>; <span class="comment">//无法连通时返回-1</span></span><br><span class="line"><span class="keyword">else</span> <span class="keyword">return</span> ans;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="拓扑排序"><a href="#拓扑排序" class="headerlink" title="拓扑排序"></a>拓扑排序</h1><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//算法思想:</span></span><br><span class="line"><span class="comment">//①定义一个队列Q,并把所有入度为0的结点加入队列</span></span><br><span class="line"><span class="comment">//②当队列不空时,取队首结点,输出然后删去所有从它出发的边,并令这些边到达的顶点的入度减1,</span></span><br><span class="line"><span class="comment">//如果某个顶点的入度减为0,则将其加入队列</span></span><br><span class="line"><span class="comment">//③反复进行②操作,直到队列为空。</span></span><br><span class="line"><span class="comment">//如果队列为空时入过队的结点数目恰好为N,说明拓扑排序成功,图G为有向无环图;否则,拓扑排序失败,图G中有环</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//拓扑排序可以判断一个给定的图是否是"有向无环图"</span></span><br><span class="line"><span class="comment">//如果有多个入度为0的顶点,选择编号最小的顶点,那么把queue改成priority_queue,</span></span><br><span class="line"><span class="comment">//并保持堆顶元素是优先队列中的最小元素即可。(set也行)</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">vector</span><<span class="keyword">int</span>> G[MAXV]; <span class="comment">//邻接表</span></span><br><span class="line"><span class="keyword">int</span> n, inDegree[MAXV];</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">topologicalSort</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="built_in">queue</span><<span class="keyword">int</span>> q;</span><br><span class="line"><span class="keyword">int</span> num = <span class="number">0</span>; <span class="comment">//记录加入拓扑排序的顶点数</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++) {</span><br><span class="line"><span class="keyword">if</span>(inDegree[i] == <span class="number">0</span>) {</span><br><span class="line">q.push(i);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">while</span>(!q.empty()) {</span><br><span class="line"><span class="keyword">int</span> u = q.front();</span><br><span class="line">q.pop();</span><br><span class="line"><span class="comment">//printf("%d ", u); //此处可输出顶点u,作为拓扑序列中的顶点</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < G[u].size(); i++) {</span><br><span class="line"><span class="keyword">int</span> v = G[u][i]; <span class="comment">//u的后继v</span></span><br><span class="line">inDegree[v]--;</span><br><span class="line"><span class="keyword">if</span>(inDegree[v] == <span class="number">0</span>) {</span><br><span class="line">q.push(v);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">G[u].clear(); <span class="comment">//清空顶点u的所有出边(可写可不写)</span></span><br><span class="line">num++; <span class="comment">//加入拓扑排序的顶点数加1</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>(num == n) <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="关键路径"><a href="#关键路径" class="headerlink" title="关键路径"></a>关键路径</h1><h2 id="AOV网-和-AOE网"><a href="#AOV网-和-AOE网" class="headerlink" title="AOV网 和 AOE网"></a>AOV网 和 AOE网</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//AOV: Activity On Vertex</span></span><br><span class="line"><span class="comment">//AOE: Activity On Edge</span></span><br><span class="line"><span class="comment">//AOV, AOE不应当有环</span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> *AOV网只有一个源点(入度为0)和一个汇点(出度为0),若有多个源点和多*个汇点,也可转化为一个源点和一个汇点的情况</span></span><br><span class="line"><span class="comment"> *即添加一个"超级源点"和一个"超级汇点",</span></span><br><span class="line"><span class="comment"> *方法:从超级源点出发,连接所有入度为0的点;从所有出度为0的点出**发,连接超级汇点;添加的有向边的边权均为0</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> *如果给定AOV网中各顶点所需要的时间,那么可以将AOV网转化成AOE网</span></span><br><span class="line"><span class="comment"> *方法:将AOV网中每个顶点都拆成两个顶点。分别表示活动的起点和终点,</span></span><br><span class="line"><span class="comment"> *而两个顶点之间用有向边连接,该有向边表示原顶点的活动,边权给定;</span></span><br><span class="line"><span class="comment"> *原AOV网中的边全部视为空活动,边权为0</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> *AOE网需要着重解决两个问题:</span></span><br><span class="line"><span class="comment"> *a. 工程起始到终止至少需要多少时间;</span></span><br><span class="line"><span class="comment"> *b. 那条(些)路径上的活动是影响整个工程进度的关键</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">//AOE网中的"最长路径"称为"关键路径",关键路径上的活动称为关键活动</span></span><br></pre></td></tr></table></figure><h2 id="最长路径算法"><a href="#最长路径算法" class="headerlink" title="最长路径算法"></a>最长路径算法</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//算法思想:</span></span><br><span class="line"><span class="comment">//把所有边的边权乘以-1,然后使用 Bellman-Ford算法 或 SPFA算法 求最长路径长度,将所得结果取反。</span></span><br><span class="line"><span class="comment">//注意:此处不能用Dijkstra算法,原因是Dijkstra算法不能处理负权边的情况。</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//最长路径问题,即 Longest Path Problem,寻求的是图中的"最长简单路径"</span></span><br><span class="line"><span class="comment">//如果图中有正环,则最长路径不存在。但最长简单路径存在,但你用Bellman-Ford算法求不出来(你说气不气)</span></span><br><span class="line"><span class="comment">//但我后面有简单方法鸭(*^▽^*) (〃'▽'〃)哪呢</span></span><br></pre></td></tr></table></figure><h2 id="关键路径算法"><a href="#关键路径算法" class="headerlink" title="关键路径算法"></a>关键路径算法</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">node</span> {</span></span><br><span class="line"><span class="keyword">int</span> v, w;</span><br><span class="line">};</span><br><span class="line"><span class="built_in">vector</span><node> G[MAXV]; <span class="comment">//邻接表</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//先求点,再夹边</span></span><br><span class="line"><span class="comment">//ve[] 事件最早发生时间 //取最大</span></span><br><span class="line"><span class="built_in">stack</span><<span class="keyword">int</span>> topOrder; <span class="comment">//留着求vl[], 不然我吃饱了撑的没事干急的啊</span></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">topologicalSort</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="built_in">queue</span><<span class="keyword">int</span>> q;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i= <span class="number">0</span>; i < n; i++) {</span><br><span class="line"><span class="keyword">if</span>(inDegree[i] == <span class="number">0</span>) {</span><br><span class="line">q.push(i);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">while</span>(!q.empty()) {</span><br><span class="line"><span class="keyword">int</span> u = q.front();</span><br><span class="line">q.pop();</span><br><span class="line">topOrder.push(u);</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < G[u].size(); i++) {</span><br><span class="line"><span class="keyword">int</span> v = G[u][i].v; <span class="comment">//u的i号后继结点编号为v</span></span><br><span class="line">inDegree[v]--;</span><br><span class="line"><span class="keyword">if</span>(inDegree[v] == <span class="number">0</span>) {</span><br><span class="line">q.push(v);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>(ve[u] + G[u][v].w > ve[v]) {</span><br><span class="line"><span class="comment">//用ve[u]来更新u的所有后继结点v</span></span><br><span class="line">ve[v] = ve[u] + G[u][v].w;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>(topOrder.size() == n) <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//vl[] 事件最晚发生时间 //取最小</span></span><br><span class="line">fill(vl,vl + n, ve[n - <span class="number">1</span>]); <span class="comment">//vl数组初始化,初始值为终点的ve值</span></span><br><span class="line"><span class="keyword">while</span>(!topOrder.empty()) {</span><br><span class="line"><span class="keyword">int</span> u = topOrder.top();</span><br><span class="line">topOrder.pop();</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < G[u].size(); i++) {</span><br><span class="line"><span class="keyword">int</span> v = G[u][i].v;</span><br><span class="line"><span class="keyword">if</span>(vl[v] - G[u][i].w < vl[u]) {</span><br><span class="line"><span class="comment">//用u的所有后继结点v的vl值来更新vl[u]</span></span><br><span class="line">vl[u] = vl[v] - G[u][i].w;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//下面代码中未保存活动的最早开始时间e和最迟开始时间l</span></span><br><span class="line"><span class="comment">//原因是e 和 l只用来判断当前活动是否为关键路径</span></span><br><span class="line"><span class="comment">//如果需要保存则在结构体node中添加域e 和 l</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">criticalPath</span><span class="params">()</span> </span>{</span><br><span class="line">menset(ve, <span class="number">0</span>, <span class="keyword">sizeof</span>(ve)); <span class="comment">//ve[]初始化</span></span><br><span class="line"><span class="keyword">if</span>(topologicalSort() == <span class="literal">false</span>) {</span><br><span class="line"><span class="keyword">return</span> <span class="number">-1</span>; <span class="comment">//不是有向无环图 返回-1</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">如果事先不知道汇点编号,可以取ve[]的最大值来得到关键路径长度</span></span><br><span class="line"><span class="comment">int maxLength = 0;</span></span><br><span class="line"><span class="comment">for(int i = 0; i < n; i++) {</span></span><br><span class="line"><span class="comment">if(maxLength < ve[i]) {</span></span><br><span class="line"><span class="comment">maxLength = ve[i];</span></span><br><span class="line"><span class="comment">}</span></span><br><span class="line"><span class="comment">}</span></span><br><span class="line"><span class="comment">fill(vl, vl + n, maxLength);</span></span><br><span class="line"><span class="comment">别忘了替换函数返回值</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line">fill(vl,vl + n, ve[n - <span class="number">1</span>]);</span><br><span class="line"><span class="keyword">while</span>(!topOrder.empty()) {</span><br><span class="line"><span class="keyword">int</span> u = topOrder.top();</span><br><span class="line">topOrder.pop();</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < G[u].size(); i++) {</span><br><span class="line"><span class="keyword">int</span> v = G[u][i].v;</span><br><span class="line"><span class="keyword">if</span>(vl[v] - G[u][i].w < vl[u]) {</span><br><span class="line"><span class="comment">//用u的所有后继结点v的vl值来更新vl[u]</span></span><br><span class="line">vl[u] = vl[v] - G[u][i].w;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="comment">//遍历邻接表的所有边,计算活动的最早开始时间e和最迟开始时间l</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> u = <span class="number">0</span>; u < n; u++) {</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < G[u][i].size(); i++) {</span><br><span class="line"><span class="keyword">int</span> v = G[u][i].v, w = G[u][i].w;</span><br><span class="line"><span class="comment">//活动的最早开始时间e和最迟开始时间l</span></span><br><span class="line"><span class="keyword">int</span> e = ve[u], l = vl[v] - w;</span><br><span class="line"><span class="comment">//如果e == l,说明活动u->v是关键活动</span></span><br><span class="line"><span class="keyword">if</span>(e == l) {</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d->%d\n"</span>, u, v); <span class="comment">//输出关键活动</span></span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> ve[n - <span class="number">1</span>]; <span class="comment">//返回关键路径长度</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>早起的鸟儿有虫吃</p>
</summary>
<category term="algorithm" scheme="https://cybaol.github.io/categories/algorithm/"/>
<category term="图论" scheme="https://cybaol.github.io/tags/%E5%9B%BE%E8%AE%BA/"/>
</entry>
<entry>
<title>debug</title>
<link href="https://cybaol.github.io/2019/10/24/warings/"/>
<id>https://cybaol.github.io/2019/10/24/warings/</id>
<published>2019-10-24T14:35:37.000Z</published>
<updated>2019-11-07T11:25:16.620Z</updated>
<content type="html"><![CDATA[<p>debug 之于 coder</p><a id="more"></a><p>一定一定要会debug!debug!debug!血的教训,从来都不debug的我,上课看老师debuging都不以为意,大佬们给的建议也是左耳进右耳出。花了一下午和一个晚上的时间终于把b站图标给改出来了。以后工作了面对着几千行几万行代码你能一行一行查吗?<br>还有能用框架就用框架!那效率真的不是一般的高!别傻乎乎地一行一行地去敲。</p><h1 id="发此博客引以为戒!!!"><a href="#发此博客引以为戒!!!" class="headerlink" title="发此博客引以为戒!!!"></a>发此博客引以为戒!!!</h1>]]></content>
<summary type="html">
<p>debug 之于 coder</p>
</summary>
<category term="techs" scheme="https://cybaol.github.io/categories/techs/"/>
<category term="警示" scheme="https://cybaol.github.io/tags/%E8%AD%A6%E7%A4%BA/"/>
</entry>
</feed>