CLRS 16.2贪心算法的原理
16.2-1
此處證明的思想是假設有一個最優解,然后可以由貪心算法得到此最優解。
設 S={1,2,...,n} 個商品,并已經按平均價值從高到底排序,即 viwi≥vi+1wi+1 。令 A 是分數背包的一個最優解,并假定解里面也是按照平均價值從高到底排序。假設總重量和最優解的總價值分別是 W,V。令 B 是從 S 中按照貪心算法求解得的解。
1) 總重量 W≤w1 :顯然裝入第一個商品得到最優解;
2) 總重量 W>w1 :在 A 中前幾個商品加起來為 w1 重的商品(這里的幾個可能是一個,也可能是多個,還可能是某一個商品的其中一部分)。令 B=A?{A中第一個w1重的商品}+{第一個商品的w1的重量} (即將 A 中的 w1 重的東西換成第一個商品的 w1 重量)。此時 A 的價值 {第一個w1重量的價值}+{背包中剩余的價值}。 B 的價值是 {第一個商品的w1重量的價值)}+{背包中剩余的價值}。由于 w1 的價值肯定是小于等于 v1 (此商品全部裝進去才有 v1 的價值)。因為 A 是最優解,所以 {第一個w1重量的價值}=v1(否則換了之后價值肯定提高, A 就不是最優解,矛盾)。這樣 A 的價值就和 B 的價值一樣,而 A 是最優的,則 B 也是最優的。
然后遞歸求解問題,求解 S 的 n?1 個商品,包最大重量為 W?w1 。最后得到貪心算法的最優解。
附上分數背包的簡單實現:
#include <iostream> #include <algorithm> using std::cout; using std::endl;struct goods {int weight;int value;goods():weight(0),value(0){} };bool cmp(goods a,goods b) {return a.value/a.weight > b.value/b.weight; }int greedy(goods *array,int n,int weight) //返回最終價值 {std::sort(array,array + n,cmp);int res = 0;for(int i = 0; i < n; i++){if(weight >= array[i].weight){res += array[i].value;weight -= array[i].weight;}else if(weight > 0){res += weight * (array[i].value / array[i].weight);weight = 0;break;}}return res; }int main() {int v[] = {60,100,120};int w[] = {10,20,30};goods ia[3];for(int i = 0; i < 3; i++){ia[i].value = v[i];ia[i].weight = w[i];}cout << "Value is " << greedy(ia,3,50) << endl;return 0; }16.2-2
根據書上所說,0-1背包具有最優子結構性質,若商品 i 的重量大于剩余可裝重量,我們將商品 i 從方案中刪除,否則解決方案是剩余商品重量不超過 W?wi 的價值最高方案與不選商品 i 且剩余重量不超過 W 的價值最高方案的最大者。
記 c[i,w] 是商品 1,...,i 且重量是 w 的解決方案價值,則:
c[i,w]=???0c[i?1,w]max(vi+c[i?1,w?wi],c[i?1,w])if i=0 or w=0if w_i>wif i>0 and w≥w_i
算法輸入是最大重量 W ,n 個商品以及兩個序列 v=[v1,v2,...,vn],w=[w1,w2,...,wn]
時間復雜度是 Θ(nW) 。
16.2-3
按照重量從低到高裝入即可。設解決方案是 x=(x1,x2,...,xn) ,且 w1≤w2≤...≤wn,v1≥v2≥...≥vn 。令 j 表示第一個沒被裝入的商品下標,所以 1..j?1 的商品全部裝入, j...n 的商品都沒轉入,現假設用 j...n 的某個商品替換 1...j?1 中的某個商品,此時背包的價值下降且容量變小。
16.2-4
思想就是選擇走最長的距離再補水,也就是說剩余的水不足以到達下一個補給點時就補水,否則就不補水。證明就略了。
16.2-5
算法如下:
1) 在點集中選取最小的點;
2) 取以該點為左起點的單位閉區間,然后從點集中去掉包含在該單位閉區間的所有點;
3) 重復1)-2),直到所有的點處理完畢;那么2)得到的單位閉區間集合A即為所求。
證明:首先,根據第二步肯定能得到一個解 A ,這個解包含所有的點。假設有一個最優解 B。用以最小點為左起點的單位閉區間代替 B 中包含該最小點的單位閉區間, 得到的新的解不會比 B 更差,即 A 也是最優解。
int interval(double *x,int n)//返回區間個數 {bool *isVisit = new bool[n];for(int i = 0; i < n; ++i)isVisit[i] = false;int res = 0;for(int i = 0; i < n; ++i){if(!isVisit[i]){isVisit[i] = true;++res;double max = x[i] + 1;for(int j = i + 1; j < n; ++j){if(x[j] > max)break;else isVisit[j] = true;}}}return res; }16.2-6
先求每個商品的平均價值 avgi=vi/wi,選擇一個物品作為主元 m=avgm ,對所有物品進行Paitition操作,時間是 O(n) 。將平均價值 avg 分為三個集合 L={ai:avgi<m},E={ai:avgi=m},G={ai:avgi>m} 。分別對 G,E,L 中元素求重量和得 SG,SE,SL 。
1. 如果 W<SG , 則令物體的集合為 O=G ,對集合 O 遞歸進行上述過程。
2. 如果 SG≤W≤SG+SE,則將集合 G 中的元素都放入包中,并將集合 E 總元素盡可能多的放入包中,結束。
3. 如果 SG+SE<W , 將 G,E 中元素放入包中。令物體集合 O=L ,總重 W=W?SG?SE 。遞歸進行上述過程。
每次遞歸都花費線性時間,子問題變成原來的一般規模,運行時間為 T(n)≤T(n/2)+Θ(n) ,得到 T(n)=O(n) 。
16.2-7
集合 A,B 按照非遞增的順序排序即可。
證明:對于任意的下標 i<j ,考慮 abii,abjj ,我們要證明 abiiabjj≥abjiabij 。由于集合按照非遞增順序排列,所以 ai≥aj,bi≥bj ,又 ai,aj 是正數且 bi?bj≥0 ,得 abi?bji≥abi?bjj ,兩邊同乘 abjiabjj 有 abiiabjj≥abjiabij 。
總結
以上是生活随笔為你收集整理的CLRS 16.2贪心算法的原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: leetcode第21天格雷编码
- 下一篇: [ CTF ]【天格】战队WriteUp