演算法第四章作業 | 貪心演算法
演算法第四章作業
一、貪心演算法
貪心演算法通過一系列的選擇來得到問題的的解。它所做的每一個選擇都是當前狀態下區域性最好選擇,即貪心選擇。
貪心演算法一般具有兩個重要的性質。
1.貪心選擇性質:貪心選擇性質是指所求問題的整體最優解可以通過一系列區域性最優的選擇,即貪心選擇。
在動態規劃演算法中,每步所做的選擇往往依賴於相關子問題的解。
貪心演算法所做的貪心選擇可以依賴於以往所做過的選擇,但決不依賴於將來所做的選擇,也不依賴於子問題的解。
動態規劃演算法通常以自底向上的方式解各個子問題,而貪心演算法則通常以自頂向上的方式進行,以迭代的方式做出相繼的貪心選擇,每做一次貪心選擇就將所求問題簡化為規模更小的子問題。
對於一個具體問題,要確定它是否具有貪心選擇性質,必須證明每一步所做的貪心選擇最終導致問題的整體最優解。
2.最優子結構性質
當一個問題的最優解包含其子問題的最優解時,稱此問題具有最優子結構的性質。問題的最優子結構性質是該問題可用動態規劃或貪心演算法求解的關鍵特徵。
二、汽車加油問題
1.問題描述
一輛汽車加滿油後可行駛n公里。旅途中有若干個加油站。設計一個有效演算法,指出應在哪些加油站停靠加油,使沿途加油次數最少。
2.解題思想:汽車走到離每次出發點最遠的加油站,到了最遠的加油站後再按照同樣的方法貪心。
3.題解
(1)先檢測各加油站之間的舉例,若發現其中有一個距離大於汽車加滿油能跑的舉例,則輸出
(2)否則,對加油站間的距離進行逐個掃描,並且累加記錄舉例,儘量選擇往遠處走,不能走了,即當累加舉例大於n時,就加油一次(count++), 最終統計出來的count就是最少的加油站數。
(3)程式碼如下:
#include <stdio.h>
int main() {
int n, k; scanf("%d %d", &n, &k);
int a[1005];
for (int i = 0; i <= n; i++) {
scanf("%d", &a[i]);
}
int sum = 0, count = 0, flag = 0;
a[k+1] = 0;
for (int j = 0; j <= k; j++) {
sum += a[j];
if (n - sum <= a[j+1] && n >= a[j]) {
sum = 0;
count++;
}
if (n < a[j])
flag = 1;
}
if (flag == 0)
printf("%d\n", count);
else
printf("No Solution!\n");
return 0;
}
4.演算法複雜度分析
(1)該演算法只需要對於加油站陣列進行掃描,故時間複雜度為O(n)。
(2)該演算法的空間複雜度為O(1)。
三、學習過程及結對程式設計
1.問題
(1)什麼是貪心演算法?
答:如上所述。
(2)貪心演算法與動態規劃演算法的區別是什麼?
答:動態規劃通常以自底向上(求解子問題)的方式解各子問題,而貪心演算法則通常以自頂向上(貪心區域性,但不是子問題)的方式進行,以迭代的方式做出相繼的貪心選擇,每做一次貪心選擇就將所求問題簡化為規模更小的子問題。
(3)對於具有最優子結構的問題應該選用貪心演算法還是動態規劃演算法來求解?
答:貪心法:一意孤行;動態規劃:三思而後行。實際上,貪心演算法與動態規劃演算法都要求問題具有最優子結構性質。對於具有大量重疊子問題的問題,應採用動態規劃演算法;對於需要做出貪心選擇的問題,採用貪心演算法。
2.結對程式設計情況:先自己獨立完成 -> (已完成/未完成)與partner交流思想(未完成partner幫忙查驗程式碼) -> 獨立完成
四、參考資料
1.課本《計算機演算法分析與設計》
2.https://blog.csdn.net/ii1245712564/article/details/45420061#1-3貪心演算法vs動態規劃