演算法的基礎
1. 演算法基礎之大O表示法
大O表示法是一種特殊的表示法,其用來 指出演算法的速度有多塊
注意:大O表示法指出了最糟糕情況下的運行時間
1:對於普通的簡單查找演算法,如果有100個元素,最多需要猜測100次,如果有40億個元素,最多需要40億次,即最多需要猜測的次數與元素的個數成正比,被稱為 線性時間 ,即:O(n)
2:對於二分查找演算法,100個元素最多需要猜測7次,而40億的元素也僅僅最多需猜測32次,其運行時間為 對數時間 ,即:O(logN)
下面做一個演算法執行時間增速的實驗:
採用簡單的查找演算法,我們知道,隨著所需要查找元素個數的遞增,所需要的時間也是呈線性遞增的。
而對於二分查找,其隨著查找元素的遞增,所需要的查找時間的增速是很緩慢的。( 摘自演算法簡介 )
大O表示法指出了演算法有多塊,其並沒有單位,即並非是指以秒為單位的,大O表示法讓你能夠比較操作數,用來指出演算法運行時間的增速。
簡單查詢演算法用大O表示法:O(N)
二分查找演算法用大O表示法:O(logN)
N表示的是操作數
綜上所述,我們知道了演算法的速度指的並非時間,而是操作數的增速。在談論演算法的速度時,我們說的是隨著輸入數的增加,其運行時間將會以什麼樣的速度增加。
在計算機領域中有一個非常著名的旅行商的問題,其計算時間增加的非常快。
簡介:有一位旅行商,需要前往5個城市,同時要保證旅程最短,故可考慮前往這些城市的所有可能順序,對於每一種順序,都計算出總旅程,再挑選出旅程最短的路線,5個城市就會有120種不同的排列方式。即5個城市需要120次操作,涉及6個城市時,需要720次操作,7個城市時,需要5040次操作。
綜上涉及到n個城市時,需要執行n!(n的階乘)次操作才能計算出最終需要的最短旅程路線。用大O表示法為O(N!),即 階乘時間。
如果涉及的城市數量過多,會造成計算出結果時,太陽已經下山了...
2. 演算法的基本要素有哪些
演算法通常由兩種基本要素組成分別是對數據對象的運算和操作;演算法的控制結構,即運算或操作間的順序。
演算法是指解題方案的准確而完整的描述,是一系列解決問題的清晰指令,演算法代表著用系統的方法描述解決問題的策略機制。也就是說,能夠對一定規范的輸入,在有限時間內獲得所要求的輸出。如果一個演算法有缺陷,或不適合於某個問題,執行這個演算法將不會解決這個問題。不同的演算法可能用不同的時間、空間或效率來完成同樣的任務。一個演算法的優劣可以用空間復雜度與時間復雜度來衡量。演算法中的指令描述的是一個計算,當其運行時能從一個初始狀態和(可能為空的)初始輸入開始,經過一系列有限而清晰定義的狀態,最終產生輸出並停止於一個終態。一個狀態到另一個狀態的轉移不一定是確定的。隨機化演算法在內的一些演算法,包含了一些隨機輸入。
3. 程序員開發用到的十大基本演算法
演算法一:快速排序演算法
快速排序是由東尼·霍爾所發展的一種排序演算法。在平均狀況下,排序 n 個項目要Ο(n log n)次比較。在最壞狀況下則需要Ο(n2)次比較,但這種狀況並不常見。事實上,快速排序通常明顯比其他Ο(n log n) 演算法更快,因為它的內部循環(inner loop)可以在大部分的架構上很有效率地被實現出來。
快速排序使用分治法(Divide and conquer)策略來把一個串列(list)分為兩個子串列(sub-lists)。
演算法步驟:
1 從數列中挑出一個元素,稱為 「基準」(pivot),
2 重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分區退出之後,該基準就處於數列的中間位置。這個稱為分區(partition)操作。
3 遞歸地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。
遞歸的最底部情形,是數列的大小是零或一,也就是永遠都已經被排序好了。雖然一直遞歸下去,但是這個演算法總會退出,因為在每次的迭代(iteration)中,它至少會把一個元素擺到它最後的位置去。
演算法二:堆排序演算法
堆排序(Heapsort)是指利用堆這種數據結構所設計的一種排序演算法。堆積是一個近似完全二叉樹的結構,並同時滿足堆積的性質:即子結點的鍵值或索引總是小於(或者大於)它的父節點。堆排序的平均時間復雜度為Ο(nlogn) 。
演算法步驟:
1.創建一個堆H[0..n-1]
2.把堆首(最大值)和堆尾互換
3.把堆的尺寸縮小1,並調用shift_down(0),目的是把新的數組頂端數據調整到相應位置
4.重復步驟2,直到堆的尺寸為1
演算法三:歸並排序
歸並排序(Merge sort,台灣譯作:合並排序)是建立在歸並操作上的一種有效的排序演算法。該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用。
演算法步驟:
演算法四:二分查找演算法
二分查找演算法是一種在有序數組中查找某一特定元素的搜索演算法。搜素過程從數組的中間元素開始,如果中間元素正好是要查找的元素,則搜 素過程結束;如果某一特定元素大於或者小於中間元素,則在數組大於或小於中間元素的那一半中查找,而且跟開始一樣從中間元素開始比較。如果在某一步驟數組 為空,則代表找不到。這種搜索演算法每一次比較都使搜索范圍縮小一半。折半搜索每次把搜索區域減少一半,時間復雜度為Ο(logn) 。
演算法五:BFPRT(線性查找演算法)
BFPRT演算法解決的問題十分經典,即從某n個元素的序列中選出第k大(第k小)的元素,通過巧妙的分 析,BFPRT可以保證在最壞情況下仍為線性時間復雜度。該演算法的思想與快速排序思想相似,當然,為使得演算法在最壞情況下,依然能達到o(n)的時間復雜 度,五位演算法作者做了精妙的處理。
演算法步驟:
終止條件:n=1時,返回的即是i小元素。
演算法六:DFS(深度優先搜索)
深度優先搜索演算法(Depth-First-Search),是搜索演算法的一種。它沿著樹的深度遍歷樹的節點,盡可能深的搜索樹的分 支。當節點v的所有邊都己被探尋過,搜索將回溯到發現節點v的那條邊的起始節點。這一過程一直進行到已發現從源節點可達的所有節點為止。如果還存在未被發 現的節點,則選擇其中一個作為源節點並重復以上過程,整個進程反復進行直到所有節點都被訪問為止。DFS屬於盲目搜索。
深度優先搜索是圖論中的經典演算法,利用深度優先搜索演算法可以產生目標圖的相應拓撲排序表,利用拓撲排序表可以方便的解決很多相關的圖論問題,如最大路徑問題等等。一般用堆數據結構來輔助實現DFS演算法。
演算法步驟:
上述描述可能比較抽象,舉個實例:
DFS 在訪問圖中某一起始頂點 v 後,由 v 出發,訪問它的任一鄰接頂點 w1;再從 w1 出發,訪問與 w1鄰 接但還沒有訪問過的頂點 w2;然後再從 w2 出發,進行類似的訪問,… 如此進行下去,直至到達所有的鄰接頂點都被訪問過的頂點 u 為止。
接著,退回一步,退到前一次剛訪問過的頂點,看是否還有其它沒有被訪問的鄰接頂點。如果有,則訪問此頂點,之後再從此頂點出發,進行與前述類似的訪問;如果沒有,就再退回一步進行搜索。重復上述過程,直到連通圖中所有頂點都被訪問過為止。
演算法七:BFS(廣度優先搜索)
廣度優先搜索演算法(Breadth-First-Search),是一種圖形搜索演算法。簡單的說,BFS是從根節點開始,沿著樹(圖)的寬度遍歷樹(圖)的節點。如果所有節點均被訪問,則演算法中止。BFS同樣屬於盲目搜索。一般用隊列數據結構來輔助實現BFS演算法。
演算法步驟:
演算法八:Dijkstra演算法
戴克斯特拉演算法(Dijkstra』s algorithm)是由荷蘭計算機科學家艾茲赫爾·戴克斯特拉提出。迪科斯徹演算法使用了廣度優先搜索解決非負權有向圖的單源最短路徑問題,演算法最終得到一個最短路徑樹。該演算法常用於路由演算法或者作為其他圖演算法的一個子模塊。
該演算法的輸入包含了一個有權重的有向圖 G,以及G中的一個來源頂點 S。我們以 V 表示 G 中所有頂點的集合。每一個圖中的邊,都是兩個頂點所形成的有序元素對。(u, v) 表示從頂點 u 到 v 有路徑相連。我們以 E 表示G中所有邊的集合,而邊的權重則由權重函數 w: E → [0, ∞] 定義。因此,w(u, v) 就是從頂點 u 到頂點 v 的非負權重(weight)。邊的權重可以想像成兩個頂點之間的距離。任兩點間路徑的權重,就是該路徑上所有邊的權重總和。已知有 V 中有頂點 s 及 t,Dijkstra 演算法可以找到 s 到 t的最低權重路徑(例如,最短路徑)。這個演算法也可以在一個圖中,找到從一個頂點 s 到任何其他頂點的最短路徑。對於不含負權的有向圖,Dijkstra演算法是目前已知的最快的單源最短路徑演算法。
演算法步驟:
重復上述步驟2、3,直到S中包含所有頂點,即W=Vi為止
演算法九:動態規劃演算法
動態規劃(Dynamic programming)是一種在數學、計算機科學和經濟學中使用的,通過把原問題分解為相對簡單的子問題的方式求解復雜問題的方法。 動態規劃常常適用於有重疊子問題和最優子結構性質的問題,動態規劃方法所耗時間往往遠少於樸素解法。
動態規劃背後的基本思想非常簡單。大致上,若要解一個給定問題,我們需要解其不同部分(即子問題),再合並子問題的解以得出原問題的解。 通常許多 子問題非常相似,為此動態規劃法試圖僅僅解決每個子問題一次,從而減少計算量: 一旦某個給定子問題的解已經算出,則將其記憶化存儲,以便下次需要同一個 子問題解之時直接查表。 這種做法在重復子問題的數目關於輸入的規模呈指數增長時特別有用。
關於動態規劃最經典的問題當屬背包問題。
演算法步驟:
演算法十:樸素貝葉斯分類演算法
樸素貝葉斯分類演算法是一種基於貝葉斯定理的簡單概率分類演算法。貝葉斯分類的基礎是概率推理,就是在各種條件的存在不確定,僅知其出現概率的情況下, 如何完成推理和決策任務。概率推理是與確定性推理相對應的。而樸素貝葉斯分類器是基於獨立假設的,即假設樣本每個特徵與其他特徵都不相關。
樸素貝葉斯分類器依靠精確的自然概率模型,在有監督學習的樣本集中能獲取得非常好的分類效果。在許多實際應用中,樸素貝葉斯模型參數估計使用最大似然估計方法,換言之樸素貝葉斯模型能工作並沒有用到貝葉斯概率或者任何貝葉斯模型。
盡管是帶著這些樸素思想和過於簡單化的假設,但樸素貝葉斯分類器在很多復雜的現實情形中仍能夠取得相當好的效果。
4. 演算法基礎知識(全連接層、LSTM、激勵函數)
1、全連接層作用:
全連接的一個作用是維度變換,尤其是可以把高維變到低維,同時把有用的信息保留下來。
全連接另一個作用是隱含語義的表達(embedding),把原始特徵映射到各個隱語義節點(hidden node)。對於最後一層全連接而言,就是分類的顯示表達
2、簡述LSTM如何解決梯度消失
LSTM有能力向單元狀態中移除或添加信息,通過門結構來管理,包括「遺忘門」,「輸出門」,「輸入門」。通過門讓信息選擇性通過,來去除或增加信息到細胞狀態. 模塊中sigmoid層輸出0到1之間的數字,描述了每個成分應該通過門限的程度。0表示「不讓任何成分通過」,而1表示「讓所有成分通過!
一個對RNN和LSTM分析比較好的連接 (注意理解體會一下他說的公式)
3、激勵函數:
作者這篇激勵函數寫的也很好 (我們實際中一般遇見都是非線性問題,所以對特徵做了加權線性操作需要通過非線性的激勵函數做非線性的變換)
激勵函數選擇
4、BP的反向推導( 詳細參考 )( 參考2 )
5. 演算法基礎
謹以此文,感謝我在這個學校最喜歡的兩個老師之一——肖my老師。本文基本為老師上課說講授內容加上一部分自己的感悟拼湊而來,寫作文本的目的是為自己的演算法課程留下一點點東西,站在老師肩膀上形成粗糙的框架,方便以後的復習以及深入。文筆有限,其中包含的錯誤還請多多包容,不吝賜教。
to do list:
時間復雜度中遞歸樹法;動規,分治新的感悟;
點覆蓋:一組點的集合,使得圖中所有邊都至少與該集合中一個點相連。
支配集:一組點的集合,使得圖中所有的點要麼屬於該集合,要麼與該集合相連。
最大團:在一個無向圖中找出點數最多的完全圖。
獨立集:一組點的集合,集合中的頂點兩兩不相鄰。(團轉過來)
SAT問題:也稱布爾可滿足性問題。給一組變
其中Ci被稱為句子。
點覆蓋<->獨立集<->最大團
最小割:割是一組邊集。如s-t割就是如果去掉這些邊,將把原圖劃分為兩個點集,其中一個點集包含s,一個點集包含t。(兩個是指不相連,而不是代表不存在邊相連,如反向邊)
decision problem: 是否存在。
search problem:找到一個解。
(這個還能擴展,比如decision problem在多項式時間內解決,所以他是P問題嗎)
漸進符號:
注意以上三種都是緊的,對應的兩個小寫的符號是不緊的,即如下圖所示:
概念:演算法的時間復雜度是一個函數,用於定性描述演算法的運行時間。注意,這個一個代表演算法輸入字元串長度的函數。
[注]輸入字元串長度是一個比較關鍵的理解,比如在背包問題中,其時間復雜度為O(nW),因為W不定,所以只能是一個偽多項式時間。
比較:c < log2N < n < n * Log2N < n^2 < n^3 < 2^n < 3^n < n! < n^n
大致:常數<對數<冪函數<指數函數<階乘
對於指數是n相關的進行比較,優先比較指數,再比較底數。
記住一個特例:n (logn)<n!<n n
計算:
一般來說,計算採用主方法和遞歸樹法,其中遞歸樹技巧性比較強,主方法其實也是遞歸樹推導歸納而來,且主方法能得到一個比較緊的結果。
主方法:
f(n) = af(n-b)+g(n) =>O( a^(n/b) *g(n) )
P:decision problems有一個多項式演算法。
NP(nondeterministic polynomial-time):decision problems能夠在多項式時間內驗證。
NPC:NP完全問題,首先這個問題是NP的,其次,其他所有問題都可以多項式時間內歸約到它。
NPH:如果所有NP問題都可以多項式時間歸約到某個問題,則稱該問題為NP困難。
因為NP困難問題未必可以在多項式時間內驗證一個解的正確性(即不一定是NP問題),因此即使NP完全問題有多項式時間的解(P=NP),NP困難問題依然可能沒有多項式時間的解。因此NP困難問題「至少與NP完全問題一樣難」。
一些NP問題能在多項式時間內解決,因為 P∈NP
NP難類型問題的證明:
先選好一個已知NP難的問題,然後將已知NP難問題多項式歸約到要證明的問題上。先給出這個歸約,然後再證明這個歸約的正確性。
NPC類型問題的證明:
證明一個問題Y是NPC問題,先說明Y是NP的,然後找到一個NPC問題X,將這個問題X歸約到問題Y上,即證明完成。
常見的NPC問題(重要,規約的時候有用!):
packing problems: set-packing,獨立集
覆蓋問題:集合覆蓋問題,頂點覆蓋問題
嚴格滿足問題(constraint satisfaction problems):SAT,3SAT
序列問題:哈密爾頓迴路,旅行商問題
劃分問題:3D-matching, 3著色問題
數字問題:子集合問題(子集元素之和為t),背包問題
其他:分團問題(是否存在一個規模為k的團)
規約的概念與理解
規約:意味著對問題進行轉換,例如將一個未知的問題轉換成我們能夠解決的問題,轉換的過程可能涉及到對問題的輸入輸出的轉換。
自歸約:search problem <=p decision problem
歸約:A歸約到B,也就是說,我們對A套一個函數f,在f函數的作用下形成一個新的問題,對這個問題運用B的黑盒解法,能夠解決問題A。
(B <=p A)一般說來,B問題如果可以歸約到A問題,也就是說,一個解決A問題的演算法可以被用做子函數(子程序)來解決B問題,也就是說,求解B問題不會比求解A問題更困難。因此,如果B問題是困難的,那麼A問題也就是困難的,因為不存在求解A問題的高效演算法。(最後一句不懂)
我簡單說一下我理解的規約,以X規約到Y為准,大概分成兩個方面:
註:在 三 的一些實例中細品。
概念:在對問題求解時,總是做出在當前看來是最好的選擇。
貪心的證明:先假設貪心演算法得到的解不是最優解,假設S1是貪心演算法得到的解,而S2是所有最優解中和S1具有最多相同元素的解,然後比較S1和S2,觀察S1和S2中第一個(最前面一個)不一樣的元素,然後在貪心解S2中將不一樣的元素換成S1中的那個元素得到另一個最優解S3,這樣S3和S1比S2和S1有更多相同元素,和假設S2是與S1有最多相同元素的最優解矛盾,這樣來推導S1是最優解。
我的理解:假設這個不是最優的,但是一定存在一個最優的解在某一個位置之前和我當前解結構是一樣的,那麼在這個位置,選最優解也可以選當前解,不影響最終答案。
[注]概念很簡單,但是實際操作的時候,貪心的角度很重要,同樣的貪心,方向對了,演算法就是對的。
例子:
給你一系列活動,每個活動有一個起始時間和一個結束時間,要求在活動不沖突的情況下找到一種有最多活動的安排。
對於這個問題,我們有一下幾種貪心的角度:
①將任務按照 開始時間 升序排列。
②將任務按照 結束時間 升序排列。
③將任務按照 任務時長 升序排列。
④對於每一個任務,都記錄與其他任務沖突的數量,按照 沖突數量 的升序排列。
其中1,3,4都是不可以的。
任務結束時間的貪心證明(反證法):
假設貪心不是最最優的,那我們在最優解中找一個與當前解有最相似的解。
由圖可以知道,貪心貪的就是最早結束,所以如果不是最優,那麼最優的結束時間一定晚於貪心的結束時間。
由上圖就可以證明。
最大流通常與最小割相聯系。
f 為任意一個流,cap為容量,對於任意的s-t割出來的點集(A,B),v( f ) <= cap(A, B)。
當流增加到與割的容量相等時候,就不可能再有增長空間了,稱為最大流。
對於割的容量來說,不同的割法會有不同流量,有些割法永遠不會有流達到,比如部分A = {s}, B = {V - s},這種把源點割出來的割法。
綜上,通過這種感性的認識,如果能找到一個最小的割,那麼這個割就一定是最大能跑到的流(如果流能更高的話在這個割上就會超過容量,反證。)
上圖為一條增廣路,一條增廣路即為一條s-t的路徑,在路徑上仍有流可以跑,其曾廣的流就是該條路徑上最小的剩餘容量。(相當於每找一條增廣路,就至少有一條邊達到滿流。)
直到在圖中找不到增廣路,此時已經達到了最大流。
找ST集合:把滿流的邊去掉,從S出發走到能到的點,遍歷的點就是S集合;剩下的點就屬於T集合。注意,如果找到了在找S集合的時候找到了T點,說明還可以繼續找增廣路。
[補]有一個很有趣的延伸,如多源點多終點問題。問:如果我有兩個源點s1,s2,兩個終點t1,t2,我想求一組流,使得s1-t1,s2-t2的流達到最大,是否可以加一個源點S,S與s1,s2相連,邊流無限大;加一個終點T,T與t1,t2相連,邊流無限大,然後這組ST的最大流即可。——答案是No,無法保證是s1-t1,s2-t2,有可能交錯。
例子講的感覺不是特別好,對理解感覺起不到很大作用,希望以後有新的想法後進行補充。
規約是一個重要的概念和思想。
一個圖的 最大獨立集 與 最小點覆蓋 是不相交的兩個點集,它們的並就是整個點集。
個人理解:獨立集和點覆蓋都是從點的角度進行劃分的,如果我們從邊的角度來看,①一個最小的點覆蓋即為我集合中的每一個點都盡可能與更多的邊相連,②同時,一條邊的兩個端點中,只能有一個端點在最小點覆蓋中[下注]
[注]我們假設有一條邊兩個端點(u,v)都在點覆蓋之中,首先顯然u,v都不是端點,因為假設u是端點的話只需要選擇v即可;
給一個集合S和一堆S的子集S1,S2,...,Sm,問是否存在存在k個子集,使它們的並集為S。
構造:
集合為點,集合中的元素為邊,有相同元素的邊相連。(注意如果某一元素只在一個子集中出現,應該怎麼處理呢!)
規約:在構造的圖中找最小的點覆蓋,選中的點能覆蓋所有的邊即為對應集合的並集能包含所有的元素。所以就完成了集合覆蓋到點覆蓋的規約。
構造:每個句子構造一個三角形,把對應變數但是相反取值的點相連。
規約:3SAT的有一個特點就是,每一個句子中至少有一個為真即可,每個句子都必須是真。將相同變數相反取值相連的目的就是,在最大獨立集中,比如選擇x為真,則剩下所有句子中x-ba一定不會被選中,同時由獨立集和構造出來三角形的性質可以知道,每一個句子,有且僅有一個會被選中(為真)。如上圖,x1-ba為真,x2-ba和x3任選一個為真即可滿足。
search problem <=p decision version
比如:如果能在多項式時間內找到一個哈密爾頓圈,那麼就能在多項式時間內找到一個哈密爾頓圈(刪邊)
在此再談P和NP:
我們知道有些問題是可以從搜索問題規約到判斷問題的,也就是所該問題如果能在多項式內判斷,那麼久能在多項式中搜索到,那麼我們只需要說,這個判斷問題能在多項式時間內求解,就叫做P問題,也就是上圖紅字的意思;那NP問題呢,必須要給出一個解的實例,判斷的是這個實例是否滿足求解問題,這個才是上圖中的紅字。比如,我如果能在多項式時間內判斷哈密爾頓圈是否(Yes/No)存在,那這個就是ploy-time algorithm,如果我給出了一系列點,能過多項式時間內判斷這些點能否構成哈密爾頓圈,那這個就是poly-time certifier。
構造:把一個點拆分成三個點。
構造:(下面兩個圖要連在一起看)
從行的角度看,一行代表一個變數;從列的角度來看,每三列代表一個句子。兩邊中一邊是兩個點,一邊是一個點,所以有k個句子的話,每一行有3k+3個節點。從哈密爾頓圈的答案轉到3SAT的答案看這個圈在每一行是從左到右還是從右到左。
子集和問題:給一個集合S,問是否能在集合中選取元素,使得總和為W。
構造:如下圖,按照前六行和前三列進行分割,可以分成4部分,其中1,3,4部分是固定的,即在第一部分,變數v列和 變數為v(包括變數及取反)的行對應的格子為0,其餘為0;第三部分全為0;第四部分按照12依次寫下來。第二部分,如果Ci句子中有變數v,則記為1,因為一個句子只有三個變數,可以簡單通過第二部分每一列和為3進行判定。此時集合已經構造出來,W為111444,與上面的規約相似,可以通過3SAT的簡單性質進行感性的認知。
近似的想法很簡單,要解決一個問題,我們希望能夠做到①求解結果是最優的 ②在多項式時間內解決 ③對於任意的實例都能夠通過該演算法解決。現在對於部分問題,無法完全滿足以上要求,所以就犧牲了①,但是我們希望結果不是盲目的,所以就引入了近似的概念。
近似演算法。比如2-近似,認為W為近似解,W 為最優解,在求最小值的情況下W<=2W ;在求最大值的情況下,W>=1/2W*
給m個機器和n個任務,每個任務有一個ti的執行時間,我們認為完成最後一個任務所需的時間為負載時間,希望能夠讓這個負載時間最短。
第一種:將任務依次放在機器上,當某個機器空閑時立即放入新任務。此時是2近似的。
證明:
引理1.最短時間安排是大於等於任務中時間最長的任務,L* >= max tj
我們在考慮放入最後一個任務前,根據我們放置的規則,該機器是耗時最短,也就是說,該機器此時的用時是低於除掉最後一個任務後的平均時長,更低於所有任務的平均時長(引理2);再根據引理1,最後一個任務應該是小於最優解的。
補充:
在這里,我還想討論一下這個近似演算法的中等於符號,先上結論:等號不一定能夠找到一個實例,但是可以構造出一種結構,通過取極限求得,我們認為這樣 也算是緊的。
構造實例:有m個機器,其中m(m-1)個任務的用時為1,1個任務的用時為m。肯定有一種任務集合,可以按照以下方式進行安排,此時的貪心解為19。
此時最佳的解為10,如下圖:
通過推廣可以知道此時的比為(2m-1)/m,當m取極限,能夠達到2倍。
第二種:將任務從大到小排序,然後依次放在機器上,當某個機器空閑時立即放入新任務。此時是2近似的。
引理3:如果有大於m個任務,那麼L*>=2t(m-1)。證明:t(m+1)是目前最短的任務,且目前所有機器上都有任務了,所以該任務加入時最優的情況不過是加入設備的原有任務剛好和t(m+1)相等,即等號。
(2近似)在n個點中,選取k個中心點,使得這些中心點能夠以半徑R的圓包含所有的點,讓其中最大的半徑最小,如下圖所示:
基礎:距離需要滿足的三個定理①(同一性)dist(x, x) = 0 ②(自反)dist(x, y) = dist(y, x) ③(三角不等式)dist(x, y) <=dist(x, z)+dist(z, y)
r(C)為C集合中所有點的最大覆蓋半徑。(需要求min r(C))
演算法:在點集中任選一個作為中心點,然後重復以下步驟k-1次:選取距離已選點集中最遠的點,加入點集。
證明:先假設r(C )< 1/2 * r(C)以選好的點畫半徑為1/2 * r(C)的圓,顯然可知[注],這個圓里有且僅有一個r(C )中的點。那麼根據在下圖中,根據三角不等式可以得出:
[注]在每個點上r(c )一定會包含到c點,而r(C )<1/2 * r(C),相當於大圓套小圓,所以c*一定在c的圓中。
(2近似)問題還是很好理解的,在點上加權值,要找一個點覆蓋,使得權值最小。如下圖左邊就是一個帶權的最小點覆蓋。
演算法: 任選一條邊(i, j)加上代價,這個代價從零開始,且這個代價的最大值低於i和j節點的權值。顯然,這個邊權值的最大值取決於兩個端點權值的最小值,我們認為當邊權值與點權值相等時,對應的那個點是緊的。把所有緊的點找出來即為點覆蓋。
流程:
證明:
引理:邊權之和小於等於點覆蓋的點權之和。這主要是由於涉及到一條邊上兩個點都被選(緊的)的情況,感性認知可以看上圖,縮放證明如下:
w(S)是等於所選的節點的權值之和的,等於所選節點節點所對應的邊權之和,可以把它放大到所有節點對應邊權之和,這樣因為一條邊(u, v)在u上算過一次後還要在v上算一次,所以等於邊權和的兩倍。再由上面引理可得。
主要為了線性規劃和整數規劃。
(2近似)沒啥好說的,只需要把方程構造出來就行了。
由於求解出來結果不一定是整數,所以我們認為某一點的值大於1/2,就選入點集。
證明:
因為xi+xj >=1,且都是正數,那必至少一個點是大於1/2的(反證,兩個都小於1/2則和小於1)。
給你n個物品和一個背包,每個物品有一個價值v和一個大小w,背包的容量是W,要求讓背包裝下盡可能大價值。
背包的時間復雜度:O(nW)
注意其中n表示物品的個數,無論是1個還是999個,他都是多項式的,這個很好理解。但是W就不一樣了,這是一個數字。我理解的是這個數字會很奇特,比如1.00001,比如99999,這些有可能看起來不大但是實際在處理的時候很難處理的數字,統一的來說,如果我們把這些數字放在電腦上,都會以二進制的方式存儲起來,有些數字用十進製表示很小,但是放在二進制上面就會很大,由W導致不能在多項式時間內解決(找不到一個范圍/上界來框它)。
演算法: 為了處理這個問題,我們改動了dp的狀態轉移方程,要讓這個轉移方程和W無關[注]。
此時還不是多項式的,然後我們再對value進行約。[注]
[注]這兩步中,我們把w改成v,並對v進行近似處理。OPT的含義變成了,在面對是否選擇第i個物品時,要想讓價值達到當前值,最少的weight。理由是更改後的誤差是可以忍受的:對v進行近似,結果只會出現最大價值的上下誤差,如果對w進行近似,則有可能出現該物品不能放入背包中,導致整個物品直接放棄的情況。
6. 編程的基礎演算法有哪些
1、二叉樹的每個結點至多隻有二棵子樹(不存在度大於2的結點),二叉樹的子樹有左右之分,次序不能顛倒。二叉樹的第i層至多有2^(i 1)個結點。
深度為k的二叉樹至多有2^k 1個結點;對任何一棵二叉樹T,如果其終端結點數為n0,度為2的結點數為n2,則n0 = n2 + 1。二叉樹演算法常被用於實現二叉查找樹和二叉堆。
遞歸演算法能夠解決的問題
數據的定義是按遞歸定義的。如Fibonacci函數。
問題解法按遞歸演算法實現。如Hanoi問題。
數據的結構形式是按遞歸定義的。如二叉樹、廣義表等。
7. 數據結構與演算法基礎知識
1.數據結構的邏輯結構
(1)集合結構
(2)線性結構(存在唯一的第一個元素與唯一的最後一個元素)(eg: 線性表、隊列、棧、字元串、數組、鏈表)
(3)樹形結構(一對多)
(4)圖形結構(多對多)
2.數據結構的物理(存儲)結構
(1).順序存儲結構(插入與刪除低效因為要挪動其他元素的位置。但是遍歷簡單)
(2).鏈式存儲結構(插入與刪除高效,但是遍歷低效)
3.大O表示法(注意大O表示法表達的是最壞的情況)
規則:
(1)用常數1取代其他所有的常數(注意常數0也當1算)(3 -> 1, O(1))
(2) 只保留最高階項(n^3+2n^2+5 ->n^3, O(n^3))
(3) 若存在最高階,省略與其想成的常數(2n^3 -> n^3, O(n^3))
4. 時間復雜度類型
(1)常數階
(2)線性階
(3)平方階
(4)對數階
(5)立方階
(6)nlog階
(7)指數階(O(2^n)或O(n!), 往往會造成噩夢般的時間消耗)
5. 空間復雜度(用大O表示法求解改演算法的輔助空間即可,例如用於交換變數用的臨時變數的數量)
六. 順序存儲的線性表
線性表結構特點:
(1) 存在唯一一個的被稱作」第一個」的數據元素;
(2) 存在唯一一個的被稱作」第二個」的數據元素;
(3) 除了第一個元素以外,結構中的每個數據元素均有一個前驅;
(4) 除了最後一個元素以外,結構中的每個數據元素均有一個後繼。
七. 鏈式存儲的線性表(單鏈表)
首元結點是鏈表中第一個值域不為空的結點。
頭結點是一個值域為空且處於首位的結點。
首指針可指向首元結點也可指向頭結點,但是如果指向頭結點可以更加方便的處理單鏈表的插入和刪除問題,不用再對首位做額外判斷,並且指向頭節點的指針永遠不用變化。
*注意一下單鏈表的前插法和尾插法。尾插法更符合邏輯
8. 關於演算法的基礎知識
所謂解析法(analysis algorithm)是指用解析的方法找出表示問題的前提條件與結果之間關系的數學表達式,並通過表達式的計算來實現問題求解。
在實際問題中, 有些變數的取值被限定在一個有限的范圍內。例如,一個星期內只有七天,一年只有十二個月, 一個班每周有六門課程等等。如果把這些量說明為整型, 字元型或其它類型顯然是不妥當的。 為此,C語言提供了一種稱為「枚舉」的類型。在「枚舉」類型的定義中列舉出所有可能的取值, 被說明為該「枚舉」類型的變數取值不能超過定義的范圍。應該說明的是, 枚舉類型是一種基本數據類型,而不是一種構造類型, 因為它不能再分解為任何基本類型。
9. 演算法的基本結構是什麼
演算法的基本結構是順序結構、條件分支結構、循環結構,順序結構,是最簡單的演算法結構,語句與語句之間是按從上到下的順序進行的。它是由若干個依次執行的處理步驟組成的,它也是任何一個演算法都離不開的一種演算法結構。
共同特點:
(1)只有一個入口和出口。
(2)結構內的每一部分都有機會被執行到,也就是說對每一個框來說都應當有一條從入口到出口的路徑通過它,如圖中的A,沒有一條從入口到出口的路徑通過它,就是不符合要求的演算法結構。
(3)結構內不存在死循環,即無終止的循環。
順序結構是最簡單的演算法結構,語句與語句之間是按從上到下的順序進行的。它是由若干個依次執行的處理步驟組成的,它也是任何一個演算法都離不開的一種演算法結構。
如下演算法是順序結構的:
S1:m=a。
S2:a=b。
S1:b=m。
10. 演算法設計基礎
python">#python3.7語言第一題用循環算
a=[[3,4,2],
[5,7,3],
[8,2,1],
[3,3,2.9]]
b=[[6,2,4],
[8,5,4],
[10,5,4]]
r=[[0]*3,[0]*3,[0]*3,[0]*3]
foriinrange(len(a)):
forjinrange(len(b[0])):
forkinrange(len(b)):
r[i][j]+=a[i][k]*b[k][j]
forlinr:print(l)
[70,36,36]
[116,60,60]
[74,31,44]
[71.0,35.5,35.6]
#第二題用numpy工具解
importnumpyasnp
ma=np.matrix([
[1,0,3,-1],
[2,1,0,2]])
mb=np.matrix([
[4,1,0],
[-1,1,3],
[2,0,1],
[1,3,4]])
print(ma*mb)
[[9-2-1]
[9911]]