{%hackmd @hipp0\Hippotumuxthem %} <style> .text-center{ text-align: center; //文字置中 } .text-left{ text-align: left; //文字靠左 } .text-right{ text-align: right; //文字靠右 } </style> <style> .reveal .slides { text-align: left; font-size:30px; } </style> # 演算法 --- <h2 style='color:#C4C400'> 介紹 </h2> 演算法不是程式語言。演算法是用來解決特定問題的方法與過程。 一個定義良好的計算方式,會包含單一,或一組完整的輸入,並且產生出一個值,或一組值作為輸出,如果所有輸出的值都是正確答案,則說明解決了問題。 ---- <h3 style='color:#C4C400'> 例子 </h3> 假設今天要解決一個問題是:「如何把芋頭和牛奶,做成芋頭牛奶」 1. 將芋頭切塊蒸至熟透。 2. 將芋泥蒸熟後先放入白糖攪拌均勻。 3. 再放入奶油攪拌均勻,最後加入牛奶時再將芋頭壓成泥狀即完成。 可以說這3個步驟就是把芋頭和牛奶做成芋頭牛奶的一種演算法 ---- <h3 style='color:#C4C400'> 為什麼要學演算法? </h3> - 學習演算法可以了解在不同規模下的表現和效率,性能通常決定了什麼是可行的,什麼是不可能的。 - 透過學習算法,了解不同的思維,特別在離散的框架上,很多時候和一般思維下會有一些不同的看法,以及觀點。 - 加強理論的實現,如果只懂理論,從來沒實作過,很容易會導致遇到問題的時候,根本不知道怎麼下手,或者使用了所謂的 "笨" 方法。 ---- 在電腦科學中有一條公式: ![](https://i.imgur.com/05AtLD8.png) ---- <h3 style='color:#C4C400'> 無所不能 ? </h3> 所謂的電腦,可不只單純是主機、筆電,具上述計算能力的最小單位就是一個晶片,而晶片早就被廣泛應用在我們生活之中,像是遙控器,手機,電視,火警,保全。 所以只要具備計算能力硬體在的地方我們就需要演算法,也因此有演算法可以改變世界之說。 ---- <h3 style='color:#C4C400'> 電腦並不聰明,反而很笨,對,電腦超級笨,超級無敵笨!!! </h3> 根據三個特性,發明了一種方式叫做 **Programming** 把現實世界要解決的問題變成數學,丟給電腦來幫我們做運算,所以聰明的並不是電腦,而是背後的人用聰明的方式,讓其他人誤以為電腦很強大,很聰明。 --- <h2 style='color:#C4C400'> 演算法策略 (跳過) </h2> https://hackmd.io/@HIPP0/HkYSwDwds --- <h2 style='color:#C4C400'> 演算法優劣 </h2> 常常聽到有人說,這個效率不好! 另外一個效率比較好,那到底怎麼來比較一個演算法的效率呢? ---- <h3 style='color:#C4C400'> 目標 </h3> - 描述函數在極限中的行為方式。 - 比較函數的 “大小” 的方法。 - 如何表示算法的運行時間。 - 判斷一個程式(做法)會不會 TLE - 透過測資反推所需的演算法效能 ---- <h3 style='color:#C4C400'> 簡單方程比較 </h3> 這邊簡單說一些常見的方程,在極限中的行為 非常重要的函數關係!!!! ### 指數函數 > 多項式函數 > 對數函數 > 常數函數 ---- ![image](https://hackmd.io/_uploads/Hyy6pDCxA.png) ---- <h3 style='color:#C4C400'> 符號 </h3> 然而描述一個函數有以下幾種方式 (但通常會直接用 big O 居多) - O-notation (big-o or o) - Ω-notation (big-omega) - Θ-notation - o-notation (little-o) - ω-notation (little-omega) ---- <h3 style='color:#C4C400'> 簡單一點的描述你可以看成 </h3> - O ~ <= - Ω ~ >= - Θ ~ = - o ~ < - ω ~ > 所以當我們描述兩個方程 f, g 在趨近極限的狀況 f = O(g) 你就可以大致看成成 f <= g ,以此類推 接下來來進行比較嚴謹的定義 ---- <h3 style='color:#C4C400'> O-notation (big-o or o) ☆☆☆☆☆ </h3> O-notation(大O符號)描述了函數漸近行為的上限 (upper bound):它表示一個函數的增長速度不會超過某個特定的速率。這個速率是基於最高次項的。 數學上的定義,若 f = O(g),則存在一個常數 c > 0 使得當 N 夠大的時候,對於所有 n >= N,有 f(n) <= c(g(n)) ---- <h3 style='color:#C4C400'> 舉例來說: </h3> $5x^2 + 3logx + x + 3$ = O($x^2$) $3e^x + 99x^{99}$ = O($e^x$) $3xlogx + 5x$ = O($3xlogx$) ---- <h3 style='color:#C4C400'> 推論題目效率需求 </h3> 程式 (C++) 大概一秒跑 $10^7 ~ 10^8$ 所以如果遇到 n = $10^5$,思考常見的函數 - $O(2^n)$ 很明顯不行 - $O(n^2)$ 不行因為 $n^2$ = $10^10$ - $O(nlogn)$ 可以 $nlogn$ = $10^6$ - $O(n)$ 可以 - $O(1)$ 肯定可以 ---- <h3 style='color:#C4C400'> 例子 </h3> - 判斷質數 - 美麗島 - 菜就多練 - PPAP --- <h2 style='color:#C4C400'> 常見演算法分析 </h2> ---- ### $O(n)$ ```cpp= for (int i = 0 ; i < n ; i++) { // do something } ``` ---- ### O($n^2$) ```cpp= for (int i = 0 ; i < n ; i++) { for (int j = 0 ; j < n ; j++) { // do something } } ``` ---- 注意這裡是用 big-O ,所以以下情況也是 $O(n^2)$ ```cpp= for (int i = 0 ; i < n ; i++) { for (int j = i ; j < n ; j++) { // do something } } ``` 因為 $\frac{1}{2}(n)(n+1)$ = $O(n^2)$ ---- <h3 style='color:#C4C400'> 二分 (logn) </h3> ```cpp= int arr[5] = {1,2,3,4,5}; int left = 0, right = 5; int target; cin >> target; while (left < right) { int mid = (left + right)/2; if (arr[mid] < target) { left = mid + 1; } else { right = mid; } } cout << "index = " << (left + right)/2; ``` ---- <h3 style='color:#C4C400'> 為什麼二分會是 (logn) </h3> 假設區間大小是 n ,二分的時候每次都會讓區間大小縮小一半 第 1 次找: $\frac{n}{2}$ 第 2 次找: $\frac{n}{4}$ $....$ 第 k 次找: $\frac{n}{2^k}$ 當 $\frac{n}{2^k}$ 等於 1 的時候停止搜尋 所以得到 $\frac{n}{2^k} = 1$ $k = log_2n = O(logn)$ ---- <h3 style='color:#C4C400'> 遞迴 </h3> 簡單的可以直接看出來的 (讚!) 複雜遞迴: 可以使用 master theorem 來判斷 太複雜的?? ---- <h3 style='color:#C4C400'> 輸入輸出問題 </h3> 雖然複雜度可以估計,但實際上輸入輸出的時間也是耗費很大,所以為了避免掉這個問題,會使用,但基本上 CPE 不需要用也可以。 ```cpp= ios::snyc_with_stdio(false),cin.tie(0); ``` (畢竟如果卡了輸入輸出,就看不出演算法實際效率了,例如圖論題目,需要大量 node 以及 edge 的時候,通常輸入挺龐大的) ---- <h3 style='color:#C4C400'> 常見內建函數 </h3> - memset O(N) - sort O(NlogN) - __gcd / gcd (c++17) O(logN) - lower_bound / upper_bound / equal_bound O(logN) - vector insert O(N) !! ---- <h3 style='color:#C4C400'> 練習 </h3> - E001 ----
{"title":"演算法複雜度","description":"演算法複雜度","contributors":"[{\"id\":\"b4bc52a4-04a8-4c6d-920a-32b9ab31a7f9\",\"add\":4621,\"del\":218},{\"id\":\"d5b90de4-9b8e-4a36-a782-226db16cf725\",\"add\":9,\"del\":65}]"}
   changed 8 months ago 229 views
   owned this note