題型與解法

來源:互聯網
上載者:User

我對本文的定位是題型. 高手請忽略.

本文會隨時進行必要的更新, 如果你有一些經典題目和一些經典題型, 請您一定告訴我喲~

部分摘自黑書.

 

 

動態規劃

動態規劃的兩種動機:

1. 利用遞迴的重疊子問題,進行記憶化求解,即先用遞迴法解決問題,再利用重疊子問題轉化為動態規劃.

例,

1)括弧序列

2)棋盤分割

3)決鬥

2. 把問題看成多階段決策過程.

例,

1)舞蹈家懷特先生

2)積木遊戲

可以通過增加維數的方法來消除後效應, 也可以在保持無後效應性的前提下改變狀態定義,以得到更多的重疊子問題.

當問題不具備最有子結構時,通常通過增加維數的辦法來解決.

常見模型:

1. 線性模型

例,

1)方塊消除

2)公路巡邏*

3)並行期望值*

4)高效能運算*

2. 串模型

1)模板匹配(常為s[i][j] 和 s[i][j-1] s[i-1][j]的關係)

2)不可分解的編碼*

3. 區間模型

1)青蛙的煩惱(常為d[s][L][x]從s起長度為L的一個區間, 對於某些特定問題,x可以用來選擇區間的起點)

2)排列問題 

3)最優排序二叉樹*

 

4.狀態壓縮模型

1)Bugs公司*

2)迷宮統計*

3)貪吃的九頭蛇*

 

我的分類:

一. 遞迴向下分解成更小的問題, 轉化為動態規劃向上

 

1. 分蘋果問題(pku 1664)

2. 整數分割問題(王曉東<<演算法分析與設計>>)

3. 買書問題(編程之美1.4可以看到這道題)

 

二. 背包問題

貼一份原始碼:

#include <iostream><br />#include <algorithm><br />using namespace std;</p><p>#define N 4<br />#define W 6</p><p>int opt[N+1][W+1]; //i:0~N-1, j:0~V<br />int w[N+1] = {1,2,3,4};<br />int v[N+1] = {0,2,4,5};</p><p>//用後i-N+1個物品(i,i+1,...N-1), 包的容量為j時的最大價值.</p><p>//寫法一, 較麻煩<br />int knapsack()<br />{<br />int tmp = min(w[N-1], W);<br />for(int i = 0; i < tmp; ++i)<br />opt[N-1][i] = 0;<br />for(int i = w[N-1]; i <= W; ++i)<br />opt[N-1][i] = v[N-1];</p><p>for(int i = N-2; i >= 0; --i)<br />for(int j = 0; j <= W; ++j)<br />{<br />opt[i][j] = opt[i+1][j];<br />if(j >= w[i])<br />{<br />int value = opt[i+1][j-w[i]] + v[i];<br />if(value > opt[i][j])<br />opt[i][j] = value;<br />}<br />}<br />return opt[0][W];<br />}</p><p>//寫法二, 稍微簡略<br />int knapsack2()<br />{<br />for(int i = 0; i <= W; ++i)<br />opt[N][i] = 0;</p><p>for(int i = N-1; i >= 0; --i)<br />for(int j = 0; j <= W; ++j)<br />{<br />opt[i][j] = opt[i+1][j];<br />if(j >= w[i])<br />{<br />int value = opt[i+1][j-w[i]] + v[i];<br />if(value > opt[i][j])<br />opt[i][j] = value;<br />}<br />}<br />return opt[0][W];<br />}</p><p>//節省空間的<br />int space_opt[2][W+1];<br />int space_opt_knapsack()<br />{<br />int tmp = min(w[N-1], W);<br />for(int i = 0; i < tmp; ++i)<br />opt[0][i] = 0;<br />for(int i = w[N-1]; i <= W; ++i)<br />opt[0][i] = v[N-1];</p><p>int cc = 1;<br />for(int i = N-2; i >= 0; --i)<br />{<br />cc = 0?1:0;<br />for(int j = 0; j <= W; ++j)<br />{<br />opt[(cc+1)%2][j] = opt[cc%2][j];<br />if(j >= w[i])<br />{<br />int value = opt[cc%2][j-w[i]] + v[i];<br />if(value > opt[(cc+1)%2][j])<br />opt[(cc+1)%2][j] = value;<br />}<br />}<br />}<br />return opt[cc][W];<br />}</p><p>//備忘錄法(又稱記憶化搜尋), 不需要計算的不做計算<br />int f(int i, int j)<br />{<br />if(i == N)<br />return 0;</p><p>if(opt[i][j] != -1)<br />return opt[i][j];</p><p>if(j >= w[i])<br />return max(f(i+1, j-w[i])+v[i], f(i+1, j));<br />else<br />return f(i+1, j);<br />}</p><p>void knapsack_recursion_test()<br />{<br />memset(opt, -1, sizeof(opt));<br />cout << f(0, W) << endl;<br />}</p><p>int main()<br />{<br />knapsack_recursion_test();<br />return 0;<br />}

 

雜湊法

 

一. 直接雜湊, 相當於打表, 不再多言

 

二. 直接雜湊的空間最佳化

   當某些元素已經不必要時, 我們將其刪除, 以減小空間的消耗

   比如, 在幾G空間中, 只有一個數出現了一次, 其他都出現了兩次, 對其進行hash, 每當一個ID出現兩次後, 可以將其空間釋放.

 

異或運算的運用

 

一. 利用異或尋找數列中出現奇數次的數

 

問題: 在幾G空間中, 只有一個數出現了一次, 其他都出現了兩次, 找出這個數?

因為有A^A=0 A^0 = A, 我們可以把所有數做異或運算, 所以我們可以找出這個數.

 

問題: 在幾G空間中, 所有數都出現了兩次, 結果丟失了兩個數, 如何找出這兩個數A, B?

我們可以把所有數做異或運算, 如果結果為0, 那麼說明丟失的是兩個相等的數(A=B);

否則, 丟失的是不同的兩個數, 所有數的異或不為0, 其結果必有一位為1, 那麼A,B有且就有一個的這一位也為1.

我們把所有數根據這一位分為兩類, 一類這位為0, 一類這位為1,假設第一類含A, 第二類含B, 那麼第一類所有數的異或值必為A, 第二類所有數的異或值必為B.

 

待續...

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.