動態(tài)規(guī)劃例題

最優(yōu)二分搜索樹

二分搜索樹

  1. 是一棵空樹
  2. 具有下列性質(zhì)的二叉樹
    • 若左子樹不空参咙,則左子樹上所有結(jié)點(diǎn)的值均小于它的根結(jié)點(diǎn)的值
    • 若右子樹不空院崇,則右子樹上所有結(jié)點(diǎn)的值均大于它的根結(jié)點(diǎn)的值
    • 左霜旧、右子樹分別為二叉搜索樹

查詢操作

MEMBER(x,S):若x在S中則返回”yes”压汪,否則返回”no”
設(shè)有n個實(shí)數(shù)a_1<a_2<…<a_n構(gòu)成集合S
指令MEMBER(x,S)中的x可能是某個a_i,也可能不在S中。把不在S中的數(shù)按區(qū)間分為n+1類,以b_0b_1贤徒,…,b_n作為每一類數(shù)的代表(虛節(jié)點(diǎn))

定義

p_i為MEMBER (a_i,S)出現(xiàn)的頻率(i=1,2,…,n)
q_j為MEMBER (b_j,S)出現(xiàn)的頻率(j=0,1,2,…,n)
\sum_{i=1}^np_i+\sum_{j=0}^nq_j=1
定義一棵二分搜索樹的總耗費(fèi):\sum_{i=1}^np_i(depth(a_i)+1)+\sum_{j=0}^nq_j(depth(b_j))
最優(yōu)二分搜索樹即耗費(fèi)最小的二分搜索樹

分析

  • T_0是最優(yōu)二分搜索樹汇四,它的根是a_k(第k小的數(shù))
    則ak的左子樹中必然包含了{(lán)a_1a_{k-1}}接奈,ak的右子樹中必然包含了{(lán)a_{k+1}a_n}。
  • 考察一棵樹接到另一個結(jié)點(diǎn)之下構(gòu)成一棵新樹時耗費(fèi)的增加
    設(shè)有一棵由結(jié)點(diǎn)b_i通孽,a_{i+1}序宦,b_{i+1},…背苦,a_j互捌,b_j構(gòu)成的樹
    按定義該樹的耗費(fèi)為\sum_{l=i+1}^jp_l(depth(a_l)+1)+\sum_{l=i}^jq_l(depth(b_l))
    把這棵樹接到到另一個結(jié)點(diǎn)之下構(gòu)成一棵新樹時,這棵子樹中的每個結(jié)點(diǎn)的深度在新樹中均
    增加了1行剂,則該子樹在新樹中的耗費(fèi)增加了\sum_{l=i+1}^jp_l+\sum_{l=i}^jq_l=q_i+(p_{i+1}+q_{i+1})+...+(p_j+q_j)=w_{ij}
  • 任何一顆子樹中結(jié)點(diǎn)的編號都是連續(xù)的秕噪,而且,最優(yōu)樹中的任何一棵子樹厚宰,也必然
    是關(guān)于子樹中結(jié)點(diǎn)的最優(yōu)樹腌巾,因此最優(yōu)二分搜索樹具有最優(yōu)子結(jié)構(gòu)性質(zhì)
  • 若規(guī)模為m≤n-1的最優(yōu)子樹均已知,就可以通過逐一計(jì)算以a_1a_2壤躲,…城菊,a_n為根的樹的耗費(fèi)來確定(使耗費(fèi)達(dá)到最小的)根a_k并找出最優(yōu)二分搜索樹,在上述計(jì)算中,規(guī)模較械锟恕( m≤n-1 )的最優(yōu)子樹在計(jì)算中要多次被用到凌唬,因此,該問題具有高度重復(fù)性
  • T_{ij}:有一棵由結(jié)點(diǎn)b_i漏麦,a_{i+1}客税,b_{i+1},…撕贞,a_j更耻,b_j構(gòu)成的耗費(fèi)最小的樹
    樹以a_k作為根(i+1≤k≤j)
    b_ia_{i+1}捏膨,b_{i+1}秧均,…,a_{k-1}号涯,b_{k-1}在左子樹
    b_k目胡,a_{k+1}b_{k+1}链快,…誉己,a_jb_j在右子樹
    這樣的樹中耗費(fèi)最小的必然是以T_{i,k-1}為其左子樹域蜗,以T_{kj}為其右子樹
    c_{ij}是最優(yōu)子樹T_{ij}的耗費(fèi)
  • T_{ij}的總耗費(fèi)由三個部分組成
    左子樹的耗費(fèi):c_{i,k-1}+w_{i,k-1}
    右子樹的耗費(fèi):c_{kj}+w_{kj}
    根的耗費(fèi):p_k
    總耗費(fèi)=c_{i,k-1}+w_{i,k-1}+c_{k,j}+w_{k,j}$$c_{k,j}+w_{k,j}=c_{i,k-1}+c_{kj}+w_{ij}
  • 已知{p_i}(i=1,2,…,n)巨双,{q_i}(j=0,1,2,…,n)
    若已知w_{i,j-1},則根據(jù)w_{ij}=w_{i,j-1}+{p_j}+{q_j}的定義計(jì)算出w_{ij}
    所以霉祸,當(dāng)c_{i,k-1}c_{kj}已知筑累,以a_k為根的樹的最小總耗費(fèi)能在O(1)時間內(nèi)計(jì)算出來
  • 綜上,分別計(jì)算以a_{i+1},a_{i+2},...,a_j為根丝蹭,含有結(jié)點(diǎn)b_i疼阔,a_{i+1}b_{i+1}半夷,…,a_j迅细,b_j的樹的總耗費(fèi)巫橄,從中選出耗費(fèi)最小的樹,即為最優(yōu)子樹
    c_{ij}=\min_{i<k≤j}{c_{i,k-1}+c_{kj}+w_{ij}}
  • 三層循環(huán)茵典,Θ(n^3)

優(yōu)化

  • 可以證明:若最小耗費(fèi)樹T_{i,j-1}T_{i+1,j}的根分別為a_pa_q湘换,則必有⑴p≤q;⑵最小耗費(fèi)樹T_{ij}的根a_k滿足p≤k≤q
  • 因此,求\min_{i<k≤j}{c_{i,k-1}+c_{kj}+w_{ij}}時彩倚,無需在a_{i+1}~a_j間一一嘗試筹我,只需要從a_p和~a_q找一個根即可

流水作業(yè)調(diào)度

問題

n個作業(yè),m項(xiàng)任務(wù)帆离,m臺機(jī)器
設(shè)有n個任務(wù)蔬蕊,每一個作業(yè)i均被分解為m項(xiàng)任務(wù):T_{i1},T_{i2},T_{im}(1≤i≤n,故共有n×m個任務(wù))哥谷,要把這些任務(wù)安排到m臺機(jī)器上進(jìn)行加工
需要滿足條件:

  1. 每個作業(yè)i的第j項(xiàng)任務(wù)T_{ij}(1≤i≤n, 1≤j≤m) 只能安排在機(jī)器P_j上進(jìn)行加工
  2. 作業(yè)i的第j項(xiàng)任務(wù)T_{ij}(1≤i≤n, 2≤j≤m)的開始加工時間均安排在第j-1項(xiàng)任務(wù)T_{i,j-1}加工完畢之后
  3. 任何一臺機(jī)器在任何一個時刻最多只能承擔(dān)一項(xiàng)任務(wù)
    設(shè)任務(wù)T_{ij}在機(jī)器P_j上進(jìn)行加工需要的時間t_{ij}岸夯,如果所有t_{ij}(1≤i≤n, 1≤j≤m)均已給出,要找出一種安排任務(wù)的方法们妥,使得完成這n個作業(yè)的加工時間為最少猜扮,這個安排稱之為最優(yōu)流水作業(yè)調(diào)度
    流水作業(yè)調(diào)度一般均指的是非優(yōu)先調(diào)度,即任何任務(wù)一旦開始加工监婶,就不允許被中斷旅赢,直到該任務(wù)被完成

分析

  • 當(dāng)機(jī)器數(shù)m≥3時,流水作業(yè)調(diào)度問題是一個NP-hard問題惑惶。當(dāng)m=2時煮盼,該問題可有多項(xiàng)式時間的算法。
  • t_{i1}a_i(作業(yè)i在P_1上加工所需時間),t_{i2}b_i(作業(yè)i在P_2上加工所需時間)
  • 當(dāng)機(jī)器P_1空閑時集惋,則任何一個作業(yè)的第一個任務(wù)都可以立即在P_1上執(zhí)行
  • 必有一個最優(yōu)調(diào)度使得在P_1上的加工是無間斷的
  • 必有一個最優(yōu)調(diào)度使得在P_2上的加工空閑時間(從0時刻起算)為最小孕似,同時還滿足在P_1上的加工是無間斷的
  • 若在P_2上的加工次序與在P_1上的加工次序不同,則只可能增加加工時間刮刑。所以僅需要考慮在P_1P_2上加工次序完全相同的調(diào)度
  • 最優(yōu)調(diào)度具有如下性質(zhì):
    在所確定的最優(yōu)調(diào)度的排列中去掉第一個執(zhí)行作業(yè)后喉祭,剩下的作業(yè)排列仍然還是一個最優(yōu)調(diào)度,即該問題具有最優(yōu)子結(jié)構(gòu)的性質(zhì)
    在計(jì)算規(guī)模為n的作業(yè)集合的最優(yōu)調(diào)度時雷绢,該作業(yè)集合的子集合的最優(yōu)調(diào)度會被多次用到泛烙,即該問題亦具有高度重復(fù)性

求解

  • N={1,2翘紊,┅蔽氨,n}是全部作業(yè)的集合,作業(yè)集S是N的子集合即有S?N
  • 對機(jī)器P_2需等待t個時間單位以后才可以用于S中的作業(yè)加工(t也可以為0即無須等
    待)
  • 記g(S,t)為在此情況下完成S中全部作業(yè)的最短時間
    g(S,t)=min_{i∈S}{a_i+ g(S-{i},b_i+max{t-a_i,0})}
  • 當(dāng)S=N即全部作業(yè)開始加工時帆疟,t=0
  • g(N,0)=min_{1≤i≤n}{a_i+ g(N-{i},b_i)}
  • 該算法的時間復(fù)雜度為指數(shù)量級鹉究,因?yàn)樗惴ㄖ袑的每一個非空子集都要進(jìn)行一次計(jì)算,而N的非空子集共有2^n-1個踪宠,因此不能直接使用動態(tài)規(guī)劃方法來求解該問題

進(jìn)一步求解

  • Johnson不等式:min{a_j,b_i} ≥ min{a_i,b_j}
  • 當(dāng)min{a_i,a_j,b_i,b_j}為a_i或者b_j時自赔,Johnson不等式成立,此時把i排在前j排在后的調(diào)度用時較少柳琢;反之绍妨,若min{a_i,a_j,b_i,b_j}為a_j或者b_i時润脸, 則j排在前i排在后的調(diào)度用時較少
  • 推廣:當(dāng)min{a_1,a_2,┅,a_n,b_1,b_2,┅,b_n}=a_k時,則對任何i≠k他去,都有min{a_i,b_k} ≥ min{a_k, b_i}成立毙驯,故此時應(yīng)將作業(yè)k安排在最前面,作為最優(yōu)調(diào)度的第一個執(zhí)行的作業(yè);當(dāng)min{a_1,a_2,┅,a_n,b_1,b_2,┅,b_n}=b_k時灾测,則對任何i≠k爆价,都有min{a_k,b_i} ≥ min{a_i, b_k}成立,故此時應(yīng)將作業(yè)k安排在最后面行施,作為最優(yōu)調(diào)度的最后一個執(zhí)行的作業(yè)
  • n個作業(yè)中首先開工(或最后開工)的作業(yè)確定之后允坚,對剩下的n-1個作業(yè)采用相同方法可再確定其中的一個作業(yè),應(yīng)作為n-1個作業(yè)中最先或最后執(zhí)行的作業(yè);反復(fù)使用這個方法直到最后只剩一個作業(yè)為止蛾号,即可確定最優(yōu)調(diào)度
  • 為O(nlgn)

總結(jié)

  • 滿足1)高度重復(fù)性 2)最優(yōu)子結(jié)構(gòu)性質(zhì)時稠项,一般采用動態(tài)規(guī)劃法,但偶爾也可能得不到高效的算法
  • 若問題本身不是NP-hard問題鲜结,進(jìn)一步分析后就有可能獲得效率較高的算法
  • 若問題本身就是NP-hard問題展运,與其它的精確算法相比,動態(tài)規(guī)劃法性能一般不算太壞精刷, 但有時需要對動態(tài)規(guī)劃法作進(jìn)一步的加工

備忘錄LCS

備忘錄方法

  • 當(dāng)某個問題可以用動態(tài)規(guī)劃法求解,但二維數(shù)組中有相當(dāng)一部分元素在整個計(jì)算中都不會被用到
  • 因此拗胜,不需要以遞推方式逐個計(jì)算二維數(shù)組中元素,而采用備忘錄方法:數(shù)組中的元素只是在需要計(jì)算時才去計(jì)算怒允,計(jì)算采用遞歸方式埂软,值計(jì)算出來之后將其保存起來以備它用
  • 若有大量的子問題無需求解時,用備忘錄方法較省時

求解

  • 當(dāng)x_i=y_j時纫事,求C[i,j]只需知道C[i-1,j-1]勘畔,而無需用到C[i,0]~C[i,j-1]及C[i-1,j]~C[i-1,n],所以只需求出一個LCS時丽惶,可能有一些C[p,q]在整個求解過程中都不會用到
  • 將C[i,0]與C[0,j] 初始化為0炫七,其余m×n個C[i,j]全部初始化為-1
  • 若x[i]=y[j],則去檢查C[i-1,j-1]:若C[i-1,j-1]> -1(已經(jīng)計(jì)算出來)钾唬,就直接把C[i-1,j-1]+1賦 給C[i,j]万哪,返回;若C[i-1,j-1]=-1(尚未計(jì)算出來)抡秆,就遞歸調(diào)用LCS(X,Y,i-1,j-1,C) 計(jì)算出C[i-1,j-1]奕巍,然后再把C[i-1,j-1]+1賦給C[i,j],返回
  • 若x[i]不等于y[j]儒士,則檢查C[i-1,j]和C[i,j-1]:若兩者均 > -1(已經(jīng)計(jì)算出來)的止,則把max{ C[i-1,j], C[i,j-1]} 賦給C[i,j],返回乍桂;若C[i-1,j], C[i,j-1] 兩者中有一個等于-1(尚未計(jì)算出來)冲杀, 或兩者均等于-1,就遞歸調(diào)用LCS將其計(jì)算出來睹酌,然后 再把max{ C[i-1,j], C[i,j-1]} 賦給C[i,j]

最長遞增子序列問題(LIS)

問題

假設(shè)A =< a_1, ??_2, … , ??_?? >為由n個不同的實(shí)數(shù)組成的序列
遞增子序列?? =< a_{??_1}, a_{??_2}, … , a_{??_m}>
其中??_1< ??_2<…< ??_??并且a_{??_1} < a_{??_2} < … < a_{??_m}
求最大的??值

最大子段和問題

問題

n個整數(shù)序列a_1a_n权谁,求該序列形如\sum_{k=i}^ja_k的子段和的最大值
當(dāng)所有整數(shù)均為負(fù)整數(shù)時定義其最大子段和為0

分治解法

如果將所給的序列a[1..n]分為長度相等的兩段a[1:n/2]和a[n/2+1:n],分別求出這兩段最大子段和,則a[1..n]的最大子段和有三種情形:

  1. a[1:n]的最大子段和與a[1:n/2]的最大子段和相同憋沿;
  2. a[1:n]的最大子段和與a[n/2+1:n]的最大子段和相同旺芽;
  3. a[1:n]的最大子段和為\sum_{k=i}^ja_k,1≤ i ≤ n/2辐啄,n/2+1 ≤ j ≤ n
    對于1采章、2可以遞歸求解
    對于3:
    a[n/2]、a[n/2+1]在最優(yōu)子序列中
    可以在a[1:n/2]中計(jì)算出s_1=max_{1≤ i ≤ n/2}\sum_{k=i}^ja_k
    可以在a[n/2+1:n]中計(jì)算出s_2=max_{n/2+1 ≤ i ≤ n}\sum_{k=n/2+1}^ia_k
    s_1+s_2即為最優(yōu)

代碼

void MaxSubSum(int *a壶辜,int left悯舟,int right)
{
    int sum=0;
    if (left==right) sum=a[left]>0?a[left]:0;
    else{ 
        int center=(left+right)/2;
        int leftsum=MaxSubSum(a,left,center);
        int rightsum=MaxSubSum(a,center+1,right);
        int s1=0; int lefts=0;
        for(int i=center;i>=left;i--){ 
            lefts+=a[i]; 
            if (lefts>s1) s1=lefts;
        }
        int s2=0; int rights=0;
        for (int i=center+1; i<=right; i++){
            rights+=a[i]; 
            if (rights>s2) s2=rights;
        }
        sum=s1+s2;
        if (sum<leftsum) sum=leftsum;
        if (sum<rightsum) sum=rightsum;
    }
    return sum;
}

分析

算法所需的計(jì)算時間T(n)滿足典型的分治算法遞歸式:

T(n)=\left\{ \begin{aligned} O(1) && n≤c \\ 2T(n/2)+O(n) && n>c \\ \end{aligned} \right.

基于主方法和主定理,T(n)=O(nlogn)

動態(tài)規(guī)劃解法

記b[j]=max_{1≤i<j}\sum_{k=i}^ja_k砸民,1≤j≤n抵怎,則
max_{1≤i≤j≤n}\sum_{k=i}^ja[k]=max_{1≤j≤n}max_{1≤i≤j}\sum_{k=i}^ja[k]=max_{1≤j≤n}b[j]
因此,當(dāng)b[j-1]>0,b[j]=b[j-1]+a[j]岭参;否則反惕,b[j]=a[j]。得出
b[j]=max_{1≤j≤n}{b[j-1]+a[j],a[j]}

代碼

int MaxSum(int n演侯,int *a)
{
    int sum=0, b=0;//初始化最大子段和為0姿染,b[0]=0
    for (int i = 1; i <= n; i++){
        if (b>0) b+=a[i];
        else b=a[i];
        if (b>sum) sum=b;//更新當(dāng)前找到的最大子段和
    }
    return sum;
}

分析

O(n)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市秒际,隨后出現(xiàn)的幾起案子悬赏,更是在濱河造成了極大的恐慌,老刑警劉巖程癌,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舷嗡,死亡現(xiàn)場離奇詭異,居然都是意外死亡嵌莉,警方通過查閱死者的電腦和手機(jī)进萄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锐峭,“玉大人中鼠,你說我怎么就攤上這事⊙伛” “怎么了援雇?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長椎扬。 經(jīng)常有香客問我惫搏,道長具温,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任筐赔,我火速辦了婚禮铣猩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘茴丰。我一直安慰自己达皿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布贿肩。 她就那樣靜靜地躺著峦椰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪汰规。 梳的紋絲不亂的頭發(fā)上汤功,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機(jī)與錄音控轿,去河邊找鬼冤竹。 笑死,一個胖子當(dāng)著我的面吹牛茬射,可吹牛的內(nèi)容都是我干的鹦蠕。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼在抛,長吁一口氣:“原來是場噩夢啊……” “哼钟病!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起刚梭,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤肠阱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后朴读,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體屹徘,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年衅金,在試婚紗的時候發(fā)現(xiàn)自己被綠了噪伊。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡氮唯,死狀恐怖鉴吹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情惩琉,我是刑警寧澤豆励,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站瞒渠,受9級特大地震影響良蒸,放射性物質(zhì)發(fā)生泄漏技扼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一嫩痰、第九天 我趴在偏房一處隱蔽的房頂上張望淮摔。 院中可真熱鬧,春花似錦始赎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至晰搀,卻和暖如春五辽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背外恕。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工杆逗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鳞疲。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓罪郊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親尚洽。 傳聞我的和親對象是個殘疾皇子悔橄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容