時空優化演算法
❶ 計算機研究生方向,具體解釋一下計算機應用技術中的方向是什麼
計算機應用方向是一個很寬泛的概念,裡面有非常非常多的小方向,不同學校、導師的方向也不一樣。一般計算機應用方向有下面幾個小方向:機器學習、最優化、模式識別、計算機圖形學、機器視覺與圖像處理、自然語言處理、人機交互、虛擬現實……這些方向大多都需要不錯的編程能力和很好的數學功底(高數、線數、概率論、離散數學)
下面是我個人了解的方向的大概介紹:
1. 機器學習這個方向現在很火,如果學的很精通,畢業後能找到很不錯的工作。這個方向需要很多數學知識(微積分、線性代數、概率論),也需要一定編程能力,至少能把自己的想法實現。這個方向下面有很多子方向,比如自然語言處理、模式識別、數據挖掘等
2. 最優化這個方向是用優化演算法處理現有的問題,需要數值分析和一些邏輯的知識,也需要一定編程能力。
3. 計算機圖形學包括一些小方向。有些研究CAD,這個不需要編程;有些研究自然景物的模擬(比如水流、頭發、火焰),需要微積分、線性代數的知識,有時會用到流體力學的公式,這個方向需要熟悉一些圖形介面(openGL、D3D)。
4. 圖像處理這個方向需要一些信號處理方面的知識。
5. 剩下的還有比如人機交互、虛擬現實、機器視覺等,都是一些交叉的方向,設計一些方法解決現有的問題
如果具體還有什麼問題,可以追問。
❷ 選擇三種數學建模方法,介紹其內容並說明其適用的問題類型,並舉例
摘要 對於大家來說,建模是大家覺得比較難的內容。那麼如何進行有效的建模呢?今天,滬江小編就為大家分享幾種常用的數學建模方法,一起來看看吧!
❸ 關於動態規劃演算法,哪位可以講一下自己心得體會
動態規劃的特點及其應用
安徽 張辰
動態規劃 階段
動態規劃是信息學競賽中的常見演算法,本文的主要內容就是分析它的特點。
文章的第一部分首先探究了動態規劃的本質,因為動態規劃的特點是由它的本質所決定的。第二部分從動態規劃的設計和實現這兩個角度分析了動態規劃的多樣性、模式性、技巧性這三個特點。第三部分將動態規劃和遞推、搜索、網路流這三個相關演算法作了比較,從中探尋動態規劃的一些更深層次的特點。
文章在分析動態規劃的特點的同時,還根據這些特點分析了我們在解題中應該怎樣利用這些特點,怎樣運用動態規劃。這對我們的解題實踐有一定的指導意義。
動態規劃是編程解題的一種重要的手段,在如今的信息學競賽中被應用得越來越普遍。最近幾年的信息學競賽,不分大小,幾乎每次都要考察到這方面的內容。因此,如何更深入地了解動態規劃,從而更為有效地運用這個解題的有力武器,是一個值得深入研究的問題。
要掌握動態規劃的應用技巧,就要了解它的各方面的特點。首要的,是要深入洞悉動態規劃的本質。
§1動態規劃的本質
動態規劃是在本世紀50年代初,為了解決一類多階段決策問題而誕生的。那麼,什麼樣的問題被稱作多階段決策問題呢?
§1.1多階段決策問題
說到多階段決策問題,人們很容易舉出下面這個例子。
[例1] 多段圖中的最短路徑問題:在下圖中找出從A1到D1的最短路徑。
仔細觀察這個圖不難發現,它有一個特點。我們將圖中的點分為四類(圖中的A、B、C、D),那麼圖中所有的邊都處於相鄰的兩類點之間,並且都從前一類點指向後一類點。這樣,圖中的邊就被分成了三類(AàB、BàC、CàD)。我們需要從每一類中選出一條邊來,組成從A1到D1的一條路徑,並且這條路徑是所有這樣的路徑中的最短者。
從上面的這個例子中,我們可以大概地了解到什麼是多階段決策問題。更精確的定義如下:
多階段決策過程,是指這樣的一類特殊的活動過程,問題可以按時間順序分解成若干相互聯系的階段,在每一個階段都要做出決策,全部過程的決策是一個決策序列[1]。要使整個活動的總體效果達到最優的問題,稱為多階段決策問題。
從上述的定義中,我們可以明顯地看出,這類問題有兩個要素。一個是階段,一個是決策。
§1.2階段與狀態
階段:將所給問題的過程,按時間或空間特徵分解成若干相互聯系的階段,以便按次序去求每階段的解。常用字母k表示階段變數。[1]
階段是問題的屬性。多階段決策問題中通常存在著若干個階段,如上面的例子,就有A、B、C、D這四個階段。在一般情況下,階段是和時間有關的;但是在很多問題(我的感覺,特別是信息學問題)中,階段和時間是無關的。從階段的定義中,可以看出階段的兩個特點,一是「相互聯系」,二是「次序」。
階段之間是怎樣相互聯系的?就是通過狀態和狀態轉移。
狀態:各階段開始時的客觀條件叫做狀態。描述各階段狀態的變數稱為狀態變數,常用sk表示第k階段的狀態變數,狀態變數sk的取值集合稱為狀態集合,用Sk表示。[1]
狀態是階段的屬性。每個階段通常包含若干個狀態,用以描述問題發展到這個階段時所處在的一種客觀情況。在上面的例子中,行人從出發點A1走過兩個階段之後,可能出現的情況有三種,即處於C1、C2或C3點。那麼第三個階段就有三個狀態S3=。
每個階段的狀態都是由以前階段的狀態以某種方式「變化」而來,這種「變化」稱為狀態轉移(暫不定義)。上例中C3點可以從B1點過來,也可以從B2點過來,從階段2的B1或B2狀態走到階段3的C3狀態就是狀態轉移。狀態轉移是導出狀態的途徑,也是聯系各階段的途徑。
說到這里,可以提出應用動態規劃的一個重要條件。那就是將各階段按照一定的次序排列好之後,對於某個給定的階段狀態,它以前各階段的狀態無法直接影響它未來的發展,而只能通過當前的這個狀態。換句話說,每個狀態都是「過去歷史的一個完整總結[1]」。這就是無後效性。對這個性質,下文還將會有解釋。
§1.3決策和策略
上面的階段與狀態只是多階段決策問題的一個方面的要素,下面是另一個方面的要素——決策。
決策:當各段的狀態取定以後,就可以做出不同的決定,從而確定下一階段的狀態,這種決定稱為決策。表示決策的變數,稱為決策變數,常用uk(sk)表示第k階段當狀態為sk時的決策變數。在實際問題中,決策變數的取值往往限制在一定范圍內,我們稱此范圍為允許決策集合。常用Dk(sk)表示第k階段從狀態sk出發的允許決策集合。顯然有uk(sk) ?Dk(sk)。[1]
決策是問題的解的屬性。決策的目的就是「確定下一階段的狀態」,還是回到上例,從階段2的B1狀態出發有三條路,也就是三個決策,分別導向階段3的C1、C2、C3三個狀態,即D2(B1)=。
有了決策,我們可以定義狀態轉移:動態規劃中本階段的狀態往往是上一階段和上一階段的決策結果,由第k段的狀態sk和本階段的決策uk確定第k+1段的狀態sk+1的過程叫狀態轉移。狀態轉移規律的形式化表示sk+1=Tk(sk,uk)稱為狀態轉移方程。
這樣看來,似乎決策和狀態轉移有著某種聯系。我的理解,狀態轉移是決策的目的,決策是狀態轉移的途徑。
各段決策確定後,整個問題的決策序列就構成一個策略,用p1,n=表示。對每個實際問題,可供選擇的策略有一定范圍,稱為允許策略集合,記作P1,n,使整個問題達到最有效果的策略就是最優策略。[1]
說到這里,又可以提出運用動態規劃的一個前提。即這個過程的最優策略應具有這樣的性質:無論初始狀態及初始決策如何,對於先前決策所形成的狀態而言,其以後的所有決策應構成最優策略[1]。這就是最優化原理。簡言之,就是「最優策略的子策略也是最優策略」。
§1.4最優化原理與無後效性
這里,我把最優化原理定位在「運用動態規劃的前提」。這是因為,是否符合最優化原理是一個問題的本質特徵。對於不滿足最優化原理的一個多階段決策問題,整體上的最優策略p1,n同任何一個階段k上的決策uk或任何一組階段k1…k2上的子策略pk1,k2都不存在任何關系。如果要對這樣的問題動態規劃的話,我們從一開始所作的劃分階段等努力都將是徒勞的。
而我把無後效性定位在「應用動態規劃的條件」,是因為動態規劃是按次序去求每階段的解,如果一個問題有後效性,那麼這樣的次序便是不合理的。但是,我們可以通過重新劃分階段,重新選定狀態,或者增加狀態變數的個數等手段,來是問題滿足無後效性這個條件。說到底,還是要確定一個「序」。
在信息學的多階段決策問題中,絕大部分都是能夠滿足最優化原理的,但它們往往會在後效性這一點上來設置障礙。所以在解題過程中,我們會特別關心「序」。對於有序的問題,就會考慮到動態規劃;對於無序的問題,也會想方設法來使其有序。
§1.5最優指標函數和規劃方程
最優指標函數:用於衡量所選定策略優劣的數量指標稱為指標函數,最優指標函數記為fk(sk),它表示從第k段狀態sk採用最優策略p*k,n到過程終止時的最佳效益值[1]。
最優指標函數其實就是我們真正關心的問題的解。在上面的例子中,f2(B1)就表示從B1點到終點D1點的最短路徑長度。我們求解的最終目標就是f1(A1)。
最優指標函數的求法一般是一個從目標狀態出發的遞推公式,稱為規劃方程:
其中sk是第k段的某個狀態,uk是從sk出發的允許決策集合Dk(sk)中的一個決策,Tk(sk,uk)是由sk和uk所導出的第k+1段的某個狀態sk+1,g(x,uk)是定義在數值x和決策uk上的一個函數,而函數opt表示最優化,根據具體問題分別表為max或min。
,稱為邊界條件。
上例中的規劃方程就是:
邊界條件為
這里是一種從目標狀態往回推的逆序求法,適用於目標狀態確定的問題。在我們的信息學問題中,也有很多有著確定的初始狀態。當然,對於初始狀態確定的問題,我們也可以採用從初始狀態出發往前推的順序求法。事實上,這種方法對我們來說要更為直觀、更易設計一些,從而更多地出現在我們的解題過程中。
我們本節所討論的這些理論雖然不是本文的主旨,但是卻對下面要說的動態規劃的特點起著基礎性的作用。
§2動態規劃的設計與實現
上面我們討論了動態規劃的一些理論,本節我們將通過幾個例子中,動態規劃的設計與實現,來了解動態規劃的一些特點。
§2.1動態規劃的多樣性
[例2] 花店櫥窗布置問題(IOI99)試題見附錄
本題雖然是本屆IOI中較為簡單的一題,但其中大有文章可作。說它簡單,是因為它有序,因此我們一眼便可看出這題應該用動態規劃來解決。但是,如何動態規劃呢?如何劃分階段,又如何選擇狀態呢?
<方法1>以花束的數目來劃分階段。在這里,階段變數k表示的就是要布置的花束數目(前k束花),狀態變數sk表示第k束花所在的花瓶。而對於每一個狀態sk,決策就是第k-1束花應該放在哪個花瓶,用uk表示。最優指標函數fk(sk)表示前k束花,其中第k束插在第sk個花瓶中,所能取得的最大美學值。
狀態轉移方程為
規劃方程為
(其中A(i,j)是花束i插在花瓶j中的美學值)
邊界條件 (V是花瓶總數,事實上這是一個虛擬的邊界)
<方法2>以花瓶的數目來劃分階段。在這里階段變數k表示的是要佔用的花瓶數目(前k個花瓶),狀態變數sk表示前k個花瓶中放了多少花。而對於任意一個狀態sk,決策就是第sk束花是否放在第k個花瓶中,用變數uk=1或0來表示。最優指標函數fk(sk)表示前k個花瓶中插了sk束花,所能取得的最大美學值。
狀態轉移方程為
規劃方程為
邊界條件為
兩種劃分階段的方法,引出了兩種狀態表示法,兩種規劃方式,但是卻都成功地解決了問題。只不過因為決策的選擇有多有少,所以演算法的時間復雜度也就不同。[2]
這個例子具有很大的普遍性。有很多的多階段決策問題都有著不止一種的階段劃分方法,因而往往就有不止一種的規劃方法。有時各種方法所產生的效果是差不多的,但更多的時候,就像我們的例子一樣,兩種方法會在某個方面有些區別。
所以,在用動態規劃解題的時候,可以多想一想是否有其它的解法。對於不同的解法,要注意比較,好的演算法好在哪裡,差一點的演算法差在哪裡。從各種不同演算法的比較中,我們可以更深刻地領會動態規劃的構思技巧。
§2.2動態規劃的模式性
這個可能做過動態規劃的人都有體會,從我們上面對動態規劃的分析也可以看出來。動態規劃的設計都有著一定的模式,一般要經歷以下幾個步驟。
劃分階段:按照問題的時間或空間特徵,把問題分為若干個階段。注意這若干個階段一定要是有序的或者是可排序的,否則問題就無法求解。
選擇狀態:將問題發展到各個階段時所處於的各種客觀情況用不同的狀態表示出來。當然,狀態的選擇要滿足無後效性。
確定決策並寫出狀態轉移方程:之所以把這兩步放在一起,是因為決策和狀態轉移有著天然的聯系,狀態轉移就是根據上一階段的狀態和決策來導出本階段的狀態。所以,如果我們確定了決策,狀態轉移方程也就寫出來了。但事實上,我們常常是反過來做,根據相鄰兩段的各狀態之間的關系來確定決策。
寫出規劃方程(包括邊界條件):在第一部分中,我們已經給出了規劃方程的通用形式化表達式。一般說來,只要階段、狀態、決策和狀態轉移確定了,這一步還是比較簡單的。
動態規劃的主要難點在於理論上的設計,一旦設計完成,實現部分就會非常簡單。大體上的框架如下:
對f1(s1)初始化(邊界條件)
for k?2 to n(這里以順序求解為例)
對每一個sk?Sk
fk(sk)?一個極值(∞或-∞)
對每一個uk(sk)?Dk(sk)
sk-1?Tk(sk,uk)
t?g(fk-1(sk-1),uk)
y t比fk(sk)更優 n
fk(sk)?t
輸出fn(sn)
這個N-S圖雖然不能代表全部,但足可以概括大多數。少數的一些特殊的動態規劃,其實現的原理也是類似,可以類比出來。我們到現在對動態規劃的分析,主要是在理論上、設計上,原因也就在此。
掌握了動態規劃的模式性,我們在用動態規劃解題時就可以把主要的精力放在理論上的設計。一旦設計成熟,問題也就基本上解決了。而且在設計演算法時也可以按部就班地來。
但是「物極必反」,太過拘泥於模式就會限制我們的思維,扼殺優良演算法思想的產生。我們在解題時,不妨發揮一下創造性,去突破動態規劃的實現模式,這樣往往會收到意想不到的效果。[3]
§2.3動態規劃的技巧性
上面我們所說的動態規劃的模式性,主要指的是實現方面。而在設計方面,雖然它較為嚴格的步驟性,但是它的設計思想卻是沒有一定的規律可循的。這就需要我們不斷地在實踐當中去掌握動態規劃的技巧,下面僅就一個例子談一點我自己的體會。
[例3] 街道問題:在下圖中找出從左下角到右上角的最短路徑,每步只能向右方或上方走。
這是一道簡單而又典型的動態規劃題,許多介紹動態規劃的書與文章中都拿它來做例子。通常,書上的解答是這樣的:
按照圖中的虛線來劃分階段,即階段變數k表示走過的步數,而狀態變數sk表示當前處於這一階段上的哪一點(各點所對應的階段和狀態已經用ks在地圖上標明)。這時的模型實際上已經轉化成了一個特殊的多段圖。用決策變數uk=0表示向右走,uk=1表示向上走,則狀態轉移方程如下:
(這里的row是地圖豎直方向的行數)
我們看到,這個狀態轉移方程需要根據k的取值分兩種情況討論,顯得非常麻煩。相應的,把它代入規劃方程而付諸實現時,演算法也很繁。因而我們在實現時,一般是不會這么做的,而代之以下面方法:
將地圖中的點規則地編號如上,得到的規劃方程如下:
(這里Distance表示相鄰兩點間的邊長)
這樣做確實要比上面的方法簡單多了,但是它已經破壞了動態規劃的本來面目,而不存在明確的階段特徵了。如果說這種方法是以地圖中的行(A、B、C、D)來劃分階段的話,那麼它的「狀態轉移」就不全是在兩個階段之間進行的了。
也許這沒什麼大不了的,因為實踐比理論更有說服力。但是,如果我們把題目擴展一下:在地圖中找出從左下角到右上角的兩條路徑,兩條路徑中的任何一條邊都不能重疊,並且要求兩條路徑的總長度最短。這時,再用這種「簡單」的方法就不太好辦了。
如果非得套用這種方法的話,則最優指標函數就需要有四維的下標,並且難以處理兩條路徑「不能重疊」的問題。
而我們回到原先「標准」的動態規劃法,就會發現這個問題很好解決,只需要加一維狀態變數就成了。即用sk=(ak,bk)分別表示兩條路徑走到階段k時所處的位置,相應的,決策變數也增加一維,用uk=(xk,yk)分別表示兩條路徑的行走方向。狀態轉移時將兩條路徑分別考慮:
在寫規劃方程時,只要對兩條路徑走到同一個點的情況稍微處理一下,減少可選的決策個數:
從這個例子中可以總結出設計動態規劃演算法的一個技巧:狀態轉移一般是在相鄰的兩個階段之間(有時也可以在不相鄰的兩個階段間),但是盡量不要在同一個階段內進行。
動態規劃是一種很靈活的解題方法,在動態規劃演算法的設計中,類似的技巧還有很多。要掌握動態規劃的技巧,有兩條途徑:一是要深刻理解動態規劃的本質,這也是我們為什麼一開始就探討它的本質的原因;二是要多實踐,不但要多解題,還要學會從解題中探尋規律,總結技巧。
§3動態規劃與一些演算法的比較
動態規劃作為諸多解題方法中的一種,必然和其他一些演算法有著諸多聯系。從這些聯系中,我們也可以看出動態規劃的一些特點。
§3.1動態規劃與遞推
——動態規劃是最優化演算法
由於動態規劃的「名氣」如此之大,以至於很多人甚至一些資料書上都往往把一種與動態規劃十分相似的演算法,當作是動態規劃。這種演算法就是遞推。實際上,這兩種演算法還是很容易區分的。
按解題的目標來分,信息學試題主要分四類:判定性問題、構造性問題、計數問題和最優化問題。我們在競賽中碰到的大多是最優化問題,而動態規劃正是解決最優化問題的有力武器,因此動態規劃在競賽中的地位日益提高。而遞推法在處理判定性問題和計數問題方面也是一把利器。下面分別就兩個例子,談一下遞推法和動態規劃在這兩個方面的聯系。
[例4] mod 4 最優路徑問題:在下圖中找出從第1點到第4點的一條路徑,要求路徑長度mod 4的余數最小。
這個圖是一個多段圖,而且是一個特殊的多段圖。雖然這個圖的形式比一般的多段圖要簡單,但是這個最優路徑問題卻不能用動態規劃來做。因為一條從第1點到第4點的最優路徑,在它走到第2點、第3點時,路徑長度mod 4的余數不一定是最小,也就是說最優策略的子策略不一定最優——這個問題不滿足最優化原理。
但是我們可以把它轉換成判定性問題,用遞推法來解決。判斷從第1點到第k點的長度mod 4為sk的路徑是否存在,用fk(sk)來表示,則遞推公式如下:
(邊界條件)
(這里lenk,i表示從第k-1點到第k點之間的第i條邊的長度,方括弧表示「或(or)」運算)
最後的結果就是可以使f4(s4)值為真的最小的s4值。
這個遞推法的遞推公式和動態規劃的規劃方程非常相似,我們在這里借用了動態規劃的符號也就是為了更清楚地顯示這一點。其實它們的思想也是非常相像的,可以說是遞推法借用了動態規劃的思想解決了動態規劃不能解決的問題。
有的多階段決策問題(像這一題的階段特徵就很明顯),由於不能滿足最優化原理等使用動態規劃的先決條件,而無法應用動態規劃。在這時可以將最優指標函數的值當作「狀態」放到下標中去,從而變最優化問題為判定性問題,再借用動態規劃的思想,用遞推法來解決問題。
§3.2動態規劃與搜索
——動態規劃是高效率、高消費演算法
同樣是解決最優化問題,有的題目我們採用動態規劃,而有的題目我們則需要用搜索。這其中有沒有什麼規則呢?
我們知道,撇開時空效率的因素不談,在解決最優化問題的演算法中,搜索可以說是「萬能」的。所以動態規劃可以解決的問題,搜索也一定可以解決。
把一個動態規劃演算法改寫成搜索是非常方便的,狀態轉移方程、規劃方程以及邊界條件都可以直接「移植」,所不同的只是求解順序。動態規劃是自底向上的遞推求解,而搜索則是自頂向下的遞歸求解(這里指深度搜索,寬度搜索類似)。
反過來,我們也可以把搜索演算法改寫成動態規劃。狀態空間搜索實際上是對隱式圖中的點進行枚舉,這種枚舉是自頂向下的。如果把枚舉的順序反過來,變成自底向上,那麼就成了動態規劃。(當然這里有個條件,即隱式圖中的點是可排序的,詳見下一節。)
正因為動態規劃和搜索有著求解順序上的不同,這也造成了它們時間效率上的差別。在搜索中,往往會出現下面的情況:
對於上圖(a)這樣幾個狀態構成的一個隱式圖,用搜索演算法就會出現重復,如上圖(b)所示,狀態C2被搜索了兩次。在深度搜索中,這樣的重復會引起以C2為根整個的整個子搜索樹的重復搜索;在寬度搜索中,雖然這樣的重復可以立即被排除,但是其時間代價也是不小的。而動態規劃就沒有這個問題,如上圖(c)所示。
一般說來,動態規劃演算法在時間效率上的優勢是搜索無法比擬的。(當然對於某些題目,根本不會出現狀態的重復,這樣搜索和動態規劃的速度就沒有差別了。)而從理論上講,任何拓撲有序(現實中這個條件常常可以滿足)的隱式圖中的搜索演算法都可以改寫成動態規劃。但事實上,在很多情況下我們仍然不得不採用搜索演算法。那麼,動態規劃演算法在實現上還有什麼障礙嗎?
考慮上圖(a)所示的隱式圖,其中存在兩個從初始狀態無法達到的狀態。在搜索演算法中,這樣的兩個狀態就不被考慮了,如上圖(b)所示。但是動態規劃由於是自底向上求解,所以就無法估計到這一點,因而遍歷了全部的狀態,如上圖(c)所示。
一般說來,動態規劃總要遍歷所有的狀態,而搜索可以排除一些無效狀態。更重要的事搜索還可以剪枝,可能剪去大量不必要的狀態,因此在空間開銷上往往比動態規劃要低很多。
如何協調好動態規劃的高效率與高消費之間的矛盾呢?有一種折衷的辦法就是記憶化演算法。記憶化演算法在求解的時候還是按著自頂向下的順序,但是每求解一個狀態,就將它的解保存下來,以後再次遇到這個狀態的時候,就不必重新求解了。這種方法綜合了搜索和動態規劃兩方面的優點,因而還是很有實用價值的。
§3.3動態規劃與網路流
——動態規劃是易設計易實現演算法
由於圖的關系復雜而無序,一般難以呈現階段特徵(除了特殊的圖如多段圖,或特殊的分段方法如Floyd),因此動態規劃在圖論中的應用不多。但有一類圖,它的點卻是有序的,這就是有向無環圖。
在有向無環圖中,我們可以對點進行拓撲排序,使其體現出有序的特徵,從而據此劃分階段。在有向無還圖中求最短路徑的演算法[4],已經體現出了簡單的動態規劃思想。但動態規劃在圖論中還有更有價值的應用。下面先看一個例子。
[例6] N個人的街道問題:在街道問題(參見例3)中,若有N個人要從左下角走向右上角,要求他們走過的邊的總長度最大。當然,這里每個人也只能向右或向上走。下面是一個樣例,左圖是從出發地到目的地的三條路徑,右圖是他們所走過的邊,這些邊的總長度為5 + 4 + 3 + 6 + 3 + 3 + 5 + 8 + 8 + 7 + 4 + 5 + 9 + 5 + 3 = 78(不一定是最大)。
這個題目是對街道問題的又一次擴展。仿照街道問題的解題方法,我們仍然可以用動態規劃來解決本題。不過這一次是N個人同時走,狀態變數也就需要用N維來表示,。相應的,決策變數也要變成N維,uk=(uk,1,uk,2,…,uk,N)。狀態轉移方程不需要做什麼改動:
在寫規劃方程時,需要注意在第k階段,N條路徑所走過的邊的總長度的計算,在這里我就用gk(sk,uk)來表示了:
邊界條件為
可見將原來的動態規劃演算法移植到這個問題上來,在理論上還是完全可行的。但是,現在的這個動態規劃演算法的時空復雜度已經是關於N的指數函數,只要N稍微大一點,這個演算法就不可能實現了。
下面我們換一個思路,將N條路徑看成是網路中一個流量為N的流,這樣求解的目標就是使這個流的費用最大。但是本題又不同於一般的費用流問題,在每一條邊e上的流費用並不是流量和邊權的乘積 ,而是用下式計算:
為了使經典的費用流演算法適用於本題,我們需要將模型稍微轉化一下:
如圖,將每條邊拆成兩條。拆開後一條邊上有權,但是容量限制為1;另一條邊沒有容量限制,但是流過這條邊就不能計算費用了。這樣我們就把問題轉化成了一個標準的最大費用固定流問題。
這個演算法可以套用經典的最小費用最大流演算法,在此就不細說了。(參見附錄中的源程序)
這個例題是我仿照IOI97的「障礙物探測器」一題[6]編出來的。「障礙物探測器」比這一題要復雜一些,但是基本思想是相似的。類似的題目還有99年冬令營的「迷宮改造」[7]。從這些題目中都可以看到動態規劃和網路流的聯系。
推廣到一般情況,任何有向無環圖中的費用流問題在理論上說,都可以用動態規劃來解決。對於流量為N(如果流量不固定,這個N需要事先求出來)的費用流問題,用N維的變數sk=(sk,1,sk,2,…,sk,N)來描述狀態,其中sk,i?V(1£i£N)。相應的,決策也用N維的變數uk=(uk,1,uk,2,…,uk,N)來表示,其中uk,i?E(sk,i)(1£i£N),E(v)表示指向v的弧集。則狀態轉移方程可以這樣表示:
sk-1,i = uk,i的弧尾結點
規劃方程為
邊界條件為
但是,由於動態規劃演算法是指數級演算法,因而在實現中的局限性很大,僅可用於一些N非常小的題目。然而在競賽解題中,比如上面說到的IOI97以及99冬令營測試時,我們使用動態規劃的傾向性很明顯(「障礙物探測器」中,我們用的是貪心策略,求N=1或N=2時的局部最優解[8])。這主要有兩個原因:
一. 雖然網路流有著經典的演算法,但是在競賽中不可能出現經典的問題。如果要運用網路流演算法,則需要經過一番模型轉化,有時這個轉化還是相當困難的。因此在演算法的設計上,靈活巧妙的動態規劃演算法反而要更為簡單一些。
二. 網路流演算法實現起來很繁,這是被人們公認的。因而在競賽的緊張環境中,實現起來有一定模式的動態規劃演算法又多了一層優勢。
正由於動態規劃演算法在設計和實現上的簡便性,所以在N不太大時,也就是在動態規劃可行的情況下,我們還是應該盡量運用動態規劃。
§4結語
本文的內容比較雜,是我幾年來對動態規劃的參悟理解、心得體會。雖然主要的篇幅講的都是理論,但是根本的目的還是指導實踐。
動態規劃,據我認為,是當今信息學競賽中最靈活、也最能體現解題者水平的一類解題方法。本文內容雖多,不能涵蓋動態規劃之萬一。「紙上得來終覺淺,絕知此事要躬行。」要想真正領悟、理解動態規劃的思想,掌握動態規劃的解題技巧,還需要在實踐中不斷地挖掘、探索。實踐得多了,也就能體會到漸入佳境之妙了。
動態規劃,
演算法之常,
運用之妙,
存乎一心。
❹ 目標跟蹤檢測演算法(四)——多目標擴展
姓名:劉帆;學號:20021210609;學院:電子工程學院
https://blog.csdn.net/qq_34919792/article/details/89893665
【嵌牛導讀】基於深度學習的演算法在圖像和視頻識別任務中取得了廣泛的應用和突破性的進展。從圖像分類問題到行人重識別問題,深度學習方法相比傳統方法表現出極大的優勢。與行人重識別問題緊密相關的是行人的多目標跟蹤問題。
【嵌牛鼻子】深度多目標跟蹤演算法
【嵌牛提問】深度多目標跟蹤演算法有哪些?
【嵌牛正文】
第一階段(概率統計最大化的追蹤)
1)多假設多目標追蹤演算法(MHT,基於kalman在多目標上的拓展)
多假設跟蹤演算法(MHT)是非常經典的多目標跟蹤演算法,由Reid在對雷達信號的自動跟蹤研究中提出,本質上是基於Kalman濾波跟蹤演算法在多目標跟蹤問題中的擴展。
卡爾曼濾波實際上是一種貝葉斯推理的應用,通過歷史關聯的預測量和k時刻的預測量來計算後驗概率:
關聯假設的後驗分布是歷史累計概率密度的連乘,轉化為對數形式,可以看出總體後驗概率的對數是每一步觀察似然和關聯假設似然的求和。但是若同時出現多個軌跡的時候,則需要考慮可能存在的多個假設關聯。
左圖為k-3時刻三個檢測觀察和兩條軌跡的可能匹配。對於這種匹配關系,可以繼續向前預測兩幀,如圖右。得到一種三層的假設樹結構,對於假設樹根枝乾的剪枝,得到k-3時刻的最終關聯結果。隨著可能性增加,假設組合會爆炸性增多,為此,只為了保留最大關聯性,我們需要對其他的節點進行裁剪。下式為選擇方程
實際上MHT不會單獨使用,一般作為單目標追蹤的擴展添加。
2)基於檢測可信度的粒子濾波演算法
這個演算法分為兩個步驟:
1、對每一幀的檢測結果,利用貪心匹配演算法與已有的對象軌跡進行關聯。
其中tr表示一個軌跡,d是某一個檢測,他們的匹配親和度計算包含三個部分:在線更新的分類學習模型(d),用來判斷檢測結果是不是屬於軌跡tr; 軌跡的每個粒子與檢測的匹配度,採用中心距離的高斯密度函數求和(d-p)表示;與檢測尺寸大小相關的閾值函數g(tr,d),表示檢測與軌跡尺度的符合程度, 而α是預設的一個超參數。
計算出匹配親和度矩陣之後,可以採用二部圖匹配的Hungarian演算法計算匹配結果。不過作者採用了近似的貪心匹配演算法,即首先找到親和度最大的那個匹配,然後刪除這個親和度,尋找下一個匹配,依次類推。貪心匹配演算法復雜度是線性,大部分情況下,也能得到最優匹配結果。
2、利用關聯結果,計算每個對象的粒子群權重,作為粒子濾波框架中的觀察似然概率。
其中tr表示需要跟蹤的對象軌跡,p是某個粒子。指示函數I(tr)表示第一步關聯中,軌跡tr是不是關聯到某個檢測結果,當存在關聯時,計算與關聯的檢測d 的高斯密度P{n}(p-d );C{tr}§是對這個粒子的分類概率;§是粒子通過檢測演算法得到的檢測可信度,(tr)是一個加權函數,計算如下:
3)基於馬爾科夫決策的多目標跟蹤演算法
作者把目標跟蹤看作為狀態轉移的過程,轉移的過程用馬爾科夫決策過程(MDP)建模。一個馬爾科夫決策過程包括下面四個元素:(S, A, T(.),R(.))。其中S表示狀態集合,A表示動作集合,T表示狀態轉移集合,R表示獎勵函數集合。一個決策是指根據狀態s確定動作a, 即 π: SA。一個對象的跟蹤過程包括如下決策過程:
從Active狀態轉移到Tracked或者Inactive狀態:即判斷新出現的對象是否是真。
從Tracked狀態轉移到Tracked或者Lost狀態:即判斷對象是否是持續跟蹤或者暫時處於丟失狀態。
從Lost狀態轉移到Lost或者Tracked或者Inactive狀態:即判斷丟失對象是否重新被跟蹤,被終止,或者繼續處於丟失狀態。
作者設計了三個獎勵函數來描述上述決策過程:
第一個是:
即判斷新出現的對象是否為真,y(a)=1時表示轉移到跟蹤狀態,反之轉移到終止狀態。這是一個二分類問題,採用2類SVM模型學習得到。這里用了5維特徵向量:包括x-y坐標、寬、高和檢測的分數。
第二個是:
這個函數用來判斷跟蹤對象下一時刻狀態是否是出於繼續跟蹤,還是處於丟失,即跟蹤失敗。這里作者用了5個歷史模板,每個模板和當前圖像塊做光流匹配,emedFB表示光流中心偏差, 表示平均重合率。 和 是閾值。
第三個是:
這個函數用來判斷丟失對象是否重新跟蹤,或者終止,或者保持丟失狀態不變。這里當丟失狀態連續保持超過 (=50)時,則轉向終止,其他情況下通過計算M個檢測匹配,來判斷是否存在最優的匹配使上式(3-14)獎勵最大,並大於0。這里涉及兩個問題如何設計特徵以及如何學習參數。這里作者構造了12維與模板匹配相關的統計值。而參數的學習採用強化學習過程,主要思想是在犯錯時候更新二類分類器值。
第二階段 深度學習應用
1)基於對稱網路的多目標跟蹤演算法
關於Siamese網路在單目標跟蹤深度學習中有了介紹,在這里不再介紹,可以向前參考。
2)基於最小多割圖模型的多目標跟蹤演算法
上述演算法中為了匹配兩個檢測採用LUV圖像格式以及光流圖像。Tang等人在文獻中發現採用深度學習計算的類光流特徵(DeepMatching),結合表示能力更強的模型也可以得到效果很好的多目標跟蹤結果。
基於DeepMatching特徵,可以構造下列5維特徵:
其中MI,MU表示檢測矩形框中匹配的點的交集大小以及並集大小,ξv和ξw表示檢測信任度。利用這5維特徵可以學習一個邏輯回歸分類器。
同樣,為了計算邊的匹配代價,需要設計匹配特徵。這里,作者採用結合姿態對齊的疊加Siamese網路計算匹配相似度,如圖9,採用的網路模型StackNetPose具有最好的重識別性能。
綜合StackNetPose網路匹配信任度、深度光流特徵(deepMatching)和時空相關度,作者設計了新的匹配特徵向量。類似於[2], 計算邏輯回歸匹配概率。最終的跟蹤結果取得了非常突出的進步。在MOT2016測試數據上的結果如下表:
3)通過時空域關注模型學習多目標跟蹤演算法
除了採用解決目標重識別問題的深度網路架構學習檢測匹配特徵,還可以根據多目標跟蹤場景的特點,設計合適的深度網路模型來學習檢測匹配特徵。Chu等人對行人多目標跟蹤問題中跟蹤演算法發生漂移進行統計分析,發現不同行人發生交互時,互相遮擋是跟蹤演算法產生漂移的重要原因[4]。如圖10。
在這里插入圖片描述
針對這個問題,文獻[4]提出了基於空間時間關注模型(STAM)用於學習遮擋情況,並判別可能出現的干擾目標。如圖11,空間關注模型用於生成遮擋發生時的特徵權重,當候選檢測特徵加權之後,通過分類器進行選擇得到估計的目標跟蹤結果,時間關注模型加權歷史樣本和當前樣本,從而得到加權的損失函數,用於在線更新目標模型。
該過程分三步,第一步是學習特徵可見圖:
第二步是根據特徵可見圖,計算空間關注圖(Spatial Attention):
其中fatt是一個局部連接的卷積和打分操作。wtji是學習到的參數。
第三步根據空間注意圖加權原特徵圖:
對生成的加權特徵圖進行卷積和全連接網路操作,生成二元分類器判別是否是目標自身。最後用得到分類打分選擇最優的跟蹤結果。
4)基於循環網路判別融合表觀運動交互的多目標跟蹤演算法
上面介紹的演算法採用的深度網路模型都是基於卷積網路結構,由於目標跟蹤是通過歷史軌跡信息來判斷新的目標狀態,因此,設計能夠記憶歷史信息並根據歷史信息來學習匹配相似性度量的網路結構來增強多目標跟蹤的性能也是比較可行的演算法框架。
考慮從三個方面特徵計算軌跡歷史信息與檢測的匹配:表觀特徵,運動特徵,以及交互模式特徵。這三個方面的特徵融合以分層方式計算。
在底層的特徵匹配計算中,三個特徵都採用了長短期記憶模型(LSTM)。對於表觀特徵,首先採用VGG-16卷積網路生成500維的特徵ϕtA,以這個特徵作為LSTM的輸入計算循環。
對於運動特徵,取相對位移vit為基本輸入特徵,直接輸入LSTM模型計算沒時刻的輸出ϕi,對於下一時刻的檢測同樣計算相對位移vjt+1,通過全連接網路計算特徵ϕj,類似於表觀特徵計算500維特徵ϕm,並利用二元匹配分類器進行網路的預訓練。
對於交互特徵,取以目標中心位置周圍矩形領域內其他目標所佔的相對位置映射圖作為LSTM模型的輸入特徵,計算輸出特徵ϕi,對於t+1時刻的檢測計算類似的相對位置映射圖為特徵,通過全連接網路計算特徵ϕj,類似於運動模型,通過全連接網路計算500維特徵ϕI,進行同樣的分類訓練。
當三個特徵ϕA,ϕM,ϕI都計算之後拼接為完整的特徵,輸入到上層的LSTM網路,對輸出的向量進行全連接計算,然後用於匹配分類,匹配正確為1,否則為0。對於最後的網路結構,還需要進行微調,以優化整體網路性能。最後的分類打分看作為相似度用於檢測與軌跡目標的匹配計算。最終的跟蹤框架採用在線的檢測與軌跡匹配方法進行計算。
5)基於雙線性長短期循環網路模型的多目標跟蹤演算法
在對LSTM中各個門函數的設計進行分析之後,Kim等人認為僅僅用基本的LSTM模型對於表觀特徵並不是最佳的方案,在文獻[10]中,Kim等人設計了基於雙線性LSTM的表觀特徵學習網路模型。
除了利用傳統的LSTM進行匹配學習,或者類似[5]中的演算法,拼接LSTM輸出與輸入特徵,作者設計了基於乘法的雙線性LSTM模型,利用LSTM的隱含層特徵(記憶)信息與輸入的乘積作為特徵,進行匹配分類器的學習。
這里對於隱含層特徵ht-1,必須先進行重新排列(reshape)操作,然後才能乘以輸入的特徵向量xt。
其中f表示非線性激活函數,mt是新的特徵輸入。而原始的檢測圖像採用ResNet50提取2048維的特徵,並通過全連接降為256維。下表中對於不同網路結構、網路特徵維度、以及不同LSTM歷史長度時,表觀特徵的學習對跟蹤性能的影響做了驗證。
可以看出採用雙線性LSTM(bilinear LSTM)的表觀特徵性能最好,此時的歷史相關長度最佳為40,這個值遠遠超過文獻[5]中的2-4幀歷史長度。相對來說40幀歷史信息影響更接近人類的直覺。
❺ 菜鳥裹裹怎麼預約無人車
菜鳥裹裹無人車可以在「菜鳥」app上預約。無人車到達前會有簡訊和電話提醒,無人車會在指定位置等待3分鍾,在車尾輸入取件碼即可。
包裹到小區後,用戶使用手機淘寶等,可以隨時預約方便的上門時間。據悉,每台無人車可存放 18 件快遞,在小區行駛一周約1小時,充電一次可行駛40多公里。
技術原理:
菜鳥物流全鏈路「時空優化」演算法中心,專注於研究路徑規劃、實時調度及數字地圖在物流場景中的全鏈路解決方案。
該演算法目前應用於倉儲配送、快遞、菜鳥裹裹寄件、菜鳥驛站收件等物流場景。例如菜鳥倉儲的智能波次生產與手持智能設備打通,指導一線人員日常工作。在城市配送方面,天貓小店、零售通、B2B物流等多場景中,城配路徑規劃演算法指導日常貨運司機工作。
在「最後一公里」的體驗上,該演算法面向天貓超市消費者提供配送員的配送軌跡查詢及2小時到達預測服務,為菜鳥裹裹2小時上門取件提供時效預測和智能派單,為菜鳥驛站指導選址。
❻ NP問題真的很難理解
原文地址: http://m.blog.csdn.net/csshuke/article/details/74909562
希望通過這篇文章可以不僅讓計算機相關專業的人可以看懂和區分什麼是P類問題什麼是NP類問題,更希望達到的效果是非專業人士比如學文科的朋友也可以有一定程度的理解。
有一則程序員界的笑話,就是有一哥們去google面試的時候被問到一個問題是:在什麼情況下P=NP,然後他的回答是」當N=1的時候」。這是我第一次聽說P=NP問題,大概是在臨近畢業為找工作而准備的時候。
這幾天科技類新聞的頭條都被阿爾法狗大戰李世石刷爆了,雖然我也不是AI專家,但是也想從普通人的角度來寫點東西來聊聊這個有意思的事情,在搜集資料的時候又一次看到了NP問題,於是想開個小差,在寫下一篇文章《AI是怎麼下圍棋的?》之前,先說說這個NP問題哈。
最簡單的定義是這樣的:
P問題:
一個問題可以在多項式( )的時間復雜度內解決。
NP問題:
一個問題的解可以在多項式的時間內被驗證。
NP-hard問題:
任意np問題都可以在多項式時間內歸約為該問題,但該問題本身不一定是NP問題。歸約的意思是為了解決問題A,先將問題A歸約為另一個問題B,解決問題B同時也間接解決了問題A。
NPC問題:
既是NP問題,也是NP-hard問題。
這樣的定義雖然簡單,但是對於第一次接觸P、NP的人來說,就像前一陣問你什麼是「引力波」而你回答:引力波是時空的漣漪。從答案中幾乎沒有得到任何有意義的理解。所以接來來的內容希望不僅計算機相關專業的人可以看懂,希望達到的效果是文科生們也可以有一定程度的理解。
現階段雖然電腦已經非常的普及,有人用它來上網,有用它來的游戲,有用它來看片,但是很少人有還在乎電腦的本質是計算機,它在給人們的日常生活帶來娛樂和方便的同時表現的其實是其龐大的計算能力。日常生活中我們使用的各種五花八門的軟體,其實都是一組計算機程序,而程序則可以看作是一系列演算法,而我們看到的計算機的硬體的作用就是處理這些演算法。這里的所說演算法不只是簡單的加減乘除,而是包括下面這些要素:
算術運算:加減乘除等運算
邏輯運算:或、且、非等運算
關系運算:大於、小於、等於、不等於等運算
數據傳輸:輸入、輸出、賦值等運算
以及通過控制結構來控制處理這些運算或操作的順序。說到這里有點擔心有些朋友已經不是很明白了,舉個例子吧。
我們如何從n個數裡面挑出最大的數。這個簡單吧,就只需要一個一個數的對比過去就行了。具體說也就是先比較n和n-1,記下比較大的那個數,接著我們再比較記下的這個數和n-2,又記下比較大的數,這樣一直比到最後一個數。這整個比較的過程我們就可以把其叫作演算法,而這個演算法就包含了上述的這些要素。給我們的n個數就是演算法的輸入數據,我們要挑選出最大的那個數就是演算法的輸出數據,當中我們判斷大小的時候必然採用了一些基礎的算術運算或關系運算。
希望說到這里大家能夠基本理解什麼是演算法,因為接下來我要花一點時間說說什麼是演算法的時間復雜度。要計算或解決一個問題,該問題通常有一個大小規模,用n表示。我們還是引用上面的例子,從n個數裡面找出最大的那個數,這個n就是該問題的規模大小。怎麼找呢?我們要通過比較n-1次才能得到結果,這個n-1次就可以理解為所花的時間,也就是時間復雜度。再比如,將這n個數按從大至小排序,n是其規模大小,若是我們按照這樣的方法:第一次從n個數里找最大,第二次從n-1個數里找最大,以此類推,需要的比較次數就是n(n-1)/2。我們所用的方法稱之庫為演算法,那麼n(n-1)/2就是該演算法的時間復雜度。對於時間復雜度,當n足夠大時,我們只注重最高次方的那一項,其他各項可以忽略,另外,其常數系數也不重要,所以,n(n-1)/2我們只重視n的平方這一項了,記為 ,這就是該演算法對該問題的時間復雜度的專業表示。
時間復雜度其實並不是表示一個程序解決問題具體需要花多少時間,而是當問題規模擴大後,程序需要的時間長度增長得有多快。也就是說,對於高速處理數據的計算機來說,處理某一個特定數據的效率不能衡量一個程序的好壞,而應該看當這個數據的規模變大到數百倍後,程序運行時間是否還是一樣,或者也跟著慢了數百倍,或者變慢了數萬倍。不管數據有多大,程序處理花的時間始終是那麼多的,我們就說這個程序很好,具有 的時間復雜度,也稱常數級復雜度;數據規模變得有多大,花的時間也跟著變得有多長,這個程序的時間復雜度就是 ,比如找n個數中的最大值;而像冒泡排序、插入排序等,數據擴大2倍,時間變慢4倍的,屬於 的復雜度。還有一些窮舉類的演算法,所需時間長度成幾何階數上漲,這就是 的指數級復雜度,甚至 的階乘級復雜度。不會存在 的復雜度,因為前面的那個「2」是系數,根本不會影響到整個程序的時間增長。同樣地, 的復雜度也就是 的復雜度。因此,我們會說,一個 的程序的效率比 的效率低,盡管在n很小的時候,前者優於後者,但後者時間隨數據規模增長得慢,最終 的復雜度將遠遠超過 。我們也說, 的復雜度小於 的復雜度。
Ok,寫到這里總算要引入正題了,容易看的出,前面的幾類時間復雜度可以分為兩種級別:一種是 , , 等,我們把它叫做多項式級的復雜度,因為它的規模n出現在底數的位置;另一種是 和 型復雜度,它是非多項式級的,其復雜度往往計算機都不能承受。
是時候引入P、NP問題的概念了: 如果一個問題可以找到一個能在多項式的時間復雜度里解決它的演算法,那麼這個問題就屬於P問題 。而NP問題的理解並不是NotP,NP問題不是非P類問題。 NP問題是指可以在多項式的時間里驗證一個解的問題,NP問題的另一個定義是,可以在多項式的時間里猜出一個解的問題。 P類問題相信不用舉太多的例子來說明了,上面提到的找最大數,排序等問題都是P類問題,而要更好的理解NP問題需要另外舉一個例子。
大整數因式分解問題-比如有人告訴你數9938550可以分解成兩個數的乘積,你不知道到底對不對,但是如果告訴你這兩個數是1123和8850,那麼很容易就可以用最簡單的計算器進行驗證。
最短路徑問題-某頂點出發,沿圖的邊到達另一頂點所經過的路徑中,各邊上權值之和最小的一條路徑——最短路徑。
如上圖,比如告訴你從點0到點5的最短路徑是22,要驗證的話只需要0->1,加上1->5,13+9=22,時間復雜度是常量 ,假如從上圖的六個點擴大到n個點的話,驗證過程所需要的演算法時間很雜度也都是 。如果沒有告訴你最短路徑是多要,要用演算法來求解的話,我們可以這樣來「猜測」它的解:先求一個總路程不超過 100的方案,假設我們可以依靠極好的運氣「猜出」一個路線,使得總長度確實不超過100,那麼我們只需要每次猜一條路一共猜n次。接下來我們再找總長度不超過 50 的方案,找不到就將閾值提高到75…… 假設最後找到了總長度為 90 的方案,而找不到總長度小於90的方案。我們最終便在多項式時間 內「猜」到了這個旅行商問題的解是一個長度為 90 的路線。
是否有不是NP問題的問題呢?有。就是對於那些驗證解都無法在多項式時間復雜度內完成的問題。比如問:一個圖中是否不存在Hamilton迴路?
從圖中的任意一點出發,最終回到起點,路途中經過圖中每一個結點當且僅當一次,則成為哈密頓迴路。
驗證Hamilton迴路只需要把給定的路徑走一次看是不是只每個結點只經過一次,而驗證不存在Hamilton迴路則需要把每條路徑都走一遍否則不敢說不存在Hamilton迴路。
之所以要特別的定義NP問題,就在於我們不會去為那些無法在多項式時間復雜度內驗證的問題去在多項式的時間復雜度內求它的解,有點拗口,但是多看幾遍應該明白,通俗的講就是對於一個問題告訴你答案讓你去驗證都需要很長很長時間,可以相像要用演算法去求解的話必定需要更長時間。
那麼反過來說,所有的P類問題都是NP問題。也就是說,能多項式地解決一個問題,必然能多項式地驗證一個問題的解——既然正解都出來了,驗證任意給定的解也只需要比較一下就可以了,大不了再算一次給你看也只需要多項式的時間復雜度。關鍵是,人們想知道,是否所有的NP問題都是P類問題,也就是說是否所有可以用多項式時間驗證的問題,也可以在多項式時間內求解。我們可以用集合的觀點來說明。如果把所有P類問題歸為一個集合P中,把所有NP問題劃進另一個集合NP中,那麼,顯然有P屬於NP。現在,所有對NP問題的研究都集中在一個問題上,即究竟是否有P=NP? 通常所謂的「NP問題」,其實就一句話:證明或推翻P=NP。
說到這里什麼是P類問題什麼是NP類問題就講完了。可能有一些人還不是很清楚,再用通俗但不是很嚴謹的表述來總結一下。
P類問題就是指那些計算機比較容易算出答案的問題。
NP類問題就是指那些已知答案以後計算機可以比較容易地驗證答案的問題。
接下來要進入的話題是為什麼P=NP難證明,覺得枯燥的看到這里已經很好了,起碼能分清楚P和NP問題了吧,接下來的內容將比較燒腦。
我們先來看一副集合示意圖,這副圖反映的是P=NP或P!=NP時候的兩個集合的效果,其中就出現了NP-Hard和NPC兩個新的概念。要說明為什麼目前為止P是否等於NP還沒有結論,不得不先弄清楚NPC和NP-Hard。
在引入NPC之前我們先來學習一個概念-歸約。簡單地說,一個問題A可以歸約為問題B的意思是說,可以用問題B的解法解決問題A,或者說,問題A可以「變成」問題B。舉個例子,現在有兩個問題:求解一個一元一次方程和求解一個一元二次方程。那麼我們說,前者可以歸約為後者,因為知道怎麼樣解一個一元二次方程那麼一定能解出一元一次方程,因為一元一次方程是一個二次項系數為零的一元二次方程。「問題A可歸約為問題B」,那麼很容易理解問題B比問題A難,要解決問題B的時間復雜度也就應該大於或等於解決問題A的時間復雜度。而且歸約有一項重要的性質:傳遞性。如果問題A可歸約為問題B,問題B可歸約為問題C,則問題A一定可歸約為問題C,這應該很容易理解吧。現在再來說一下歸約的標准概念: 如果能找到這樣一個變化法則,對任意一個程序A的輸入,都能按這個法則變換成程序B的輸入,使兩程序的輸出相同,那麼我們說,問題A可歸約為問題B。
從歸約的定義中我們看到,一個問題歸約為另一個問題,時間復雜度增加了,問題的應用范圍也增大了。通過對某些問題的不斷歸約,我們能夠不斷尋找復雜度更高,但應用范圍更廣的演算法來代替復雜度雖然低,但只能用於很小的一類問題的演算法。那麼如果把一個NP問題不斷地歸約上去,那麼最後是否有可能找到一個時間復雜度最高,並且能「通吃」所有的NP問題的這樣一個超級NP問題?答案居然是肯定的。也就是說,存在這樣一個NP問題,所有的NP問題都可以歸約成它,並且這種問題不只一個,它有很多個,它是一類問題。這一類問題就是傳說中的NPC問題,也就是NP-完全問題。所以NPC問題的定義非常簡單。同時滿足下面兩個條件的問題就是NPC問題。 首先,它得是一個NP問題;然後,所有的NP問題都可以歸約到它。
既然所有的NP問題都能歸約成NPC問題,那麼只要任意一個NPC問題找到了一個多項式的演算法,那麼所有的NP問題都能用這個演算法解決了,那麼NP也就等於P了。因此,目前NPC問題還沒有多項式的有效演算法,只能用指數級甚至階乘級復雜度的演算法來解決,那麼意思就是如果能夠找到一個能用多項式時間復雜度解決的NPC問題就證明了P=NP了。
而說到NP-Hard問題。NP-Hard問題是這樣一種問題,它滿足NPC問題定義的第二條但不一定要滿足第一條,就是說所有的NP問題都能歸化到它,但它本身並不一定是個NP問題,也就是即使有一天發現了NPC問題的多項式演算法,但NP-Hard問題仍然無法用多項式演算法解決,因為它不是NP問題,對於答案的驗證都很困難。
下面引用Matrix67文章里的邏輯電路的例子來說明NPC問題。
邏輯電路問題是指的這樣一個問題:給定一個邏輯電路,問是否存在一種輸入使輸出為True。
什麼叫做邏輯電路呢?一個邏輯電路由若干個輸入,一個輸出,若干「邏輯門」和密密麻麻的線組成。看下面一例,不需要解釋你馬上就明白了。
這是個較簡單的邏輯電路,當輸入1、輸入2、輸入3分別為True、True、False或False、True、False時,輸出為True。
有輸出無論如何都不可能為True的邏輯電路嗎?有。下面就是一個簡單的例子。
上面這個邏輯電路中,無論輸入是什麼,輸出都是False。我們就說,這個邏輯電路不存在使輸出為True的一組輸入。
回到上文,給定一個邏輯電路,問是否存在一種輸入使輸出為True,這即邏輯電路問題。
邏輯電路問題屬於NPC問題。這是有嚴格證明的。它顯然屬於NP問題,並且可以直接證明所有的NP問題都可以歸約到它。證明過程相當復雜,其大概意思是說任意一個NP問題的輸入和輸出都可以轉換成邏輯電路的輸入和輸出(想想計算機內部也不過是一些0和1的運算),因此對於一個NP問題來說,問題轉化為了求出滿足結果為True的一個輸入(即一個可行解)。
類似這樣的NPC問題,目前還沒有找到在多項式復雜度內可以求解的演算法,所以說一旦這樣的問題都變得多項式復雜度內可解的話,很多問題都可以通過現有的計算機技術進行求解。就比如電腦下圍棋,驗證一局棋的結果顯然是很簡單的,但要保證每局都能贏的話目前的方法需要電腦窮舉出所有的可能性,並根據每一步棋的變化搜索出最終達到勝利的下棋路徑,目前的計算機性能顯然是達不到的。因為圍棋的狀態空間復雜度達到了10的172方,而圍棋的博弈樹復雜度達到了10的300次方,光看數字可能不直觀,一句話就是圍棋的變化多過宇宙的原子數量!
所以對於圍棋這樣的游戲人工智慧如果要戰勝人類需要實現下面兩個條件中的任何一個:
計算機性能無限強大,可以窮舉所有可能性;
研究出新的演算法,在不窮舉的情況下也能保證贏;
目前 Google 的 AlphaGo所做的只不過是通過優化演算法提高窮舉效率,同時利用現有的大數據與雲計算來提升計算性能而已 。下面一篇文章將更詳細的介紹AI是如何下圍棋的,敬請期待。
❼ 衡量演算法效率的方法與准則
演算法效率與分析
數據結構作為程序設計的基礎,其對演算法效率的影響必然是不可忽視的。本文就如何合理選擇數據結構來優化演算法這一問題,對選擇數據結構的原則和方法進行了一些探討。首先對數據邏輯結構的重要性進行了分析,提出了選擇邏輯結構的兩個基本原則;接著又比較了順序和鏈式兩種存儲結構的優點和缺點,並討論了選擇數據存儲結構的方法;最後本文從選擇數據結構的的另一角度出發,進一步探討了如何將多種數據結構進行結合的方法。在討論方法的同時,本文還結合實際,選用了一些較具有代表性的信息學競賽試題舉例進行了分析
【正文】一、引論
「數據結構+演算法=程序」,這就說明程序設計的實質就是對確定的問題選擇一種合適的數據結構,加上設計一種好的演算法。由此可見,數據結構在程序設計中有著十分重要的地位。
數據結構是相互之間存在一種或多種特定關系的數據元素的集合。因為這其中的「關系」,指的是數據元素之間的邏輯關系,因此數據結構又稱為數據的邏輯結構。而相對於邏輯結構這個比較抽象的概念,我們將數據結構在計算機中的表示又稱為數據的存儲結構。
建立問題的數學模型,進而設計問題的演算法,直至編出程序並進行調試通過,這就是我們解決信息學問題的一般步驟。我們要建立問題的數學模型,必須首先找出問題中各對象之間的關系,也就是確定所使用的邏輯結構;同時,設計演算法和程序實現的過程,必須確定如何實現對各個對象的操作,而操作的方法是決定於數據所採用的存儲結構的。因此,數據邏輯結構和存儲結構的好壞,將直接影響到程序的效率。
二、選擇合理的邏輯結構
在程序設計中,邏輯結構的選用就是要分析題目中的數據元素之間的關系,並根據這些特定關系來選用合適的邏輯結構以實現對問題的數學描述,進一步解決問題。邏輯結構實際上是用數學的方法來描述問題中所涉及的操作對象及對象之間的關系,將操作對象抽象為數學元素,將對象之間的復雜關系用數學語言描述出來。
根據數據元素之間關系的不同特性,通常有以下四種基本邏輯結構:集合、線性結構、樹形結構、圖狀(網狀)結構。這四種結構中,除了集合中的數據元素之間只有「同屬於一個集合」的關系外,其它三種結構數據元素之間分別為「一對一」、「一對多」、「多對多」的關系。
因此,在選擇邏輯結構之前,我們應首先把題目中的操作對象和對象之間的關系分析清楚,然後再根據這些關系的特點來合理的選用邏輯結構。尤其是在某些復雜的問題中,數據之間的關系相當復雜,且選用不同邏輯結構都可以解決這一問題,但選用不同邏輯結構實現的演算法效率大不一樣。
對於這一類問題,我們應採用怎樣的標准對邏輯結構進行選擇呢?
下文將探討選擇合理邏輯結構應充分考慮的兩個因素。
一、 充分利用「可直接使用」的信息。
首先,我們這里所講的「信息」,指的是元素與元素之間的關系。
對於待處理的信息,大致可分為「可直接使用」和「不可直接使用」兩類。對於「可直接使用」的信息,我們使用時十分方便,只需直接拿來就可以了。而對於「不可直接使用」的這一類,我們也可以通過某些間接的方式,使之成為可以使用的信息,但其中轉化的過程顯然是比較浪費時間的。
由此可見,我們所需要的是盡量多的「可直接使用」的信息。這樣的信息越多,演算法的效率就會越高。
對於不同的邏輯結構,其包含的信息是不同的,演算法對信息的利用也會出現不同的復雜程度。因此,要使演算法能夠充分利用「可直接使用」的信息,而避免演算法在信息由「不可直接使用」向「可直接使用」的轉化過程中浪費過多的時間,我們必然需要採用一種合理的邏輯結構,使其包含更多「可直接使用」的信息。
〖問題一〗 IOI99的《隱藏的碼字》。
〖問題描述〗
問題中給出了一些碼字和一個文本,要求編程找出文本中包含這些碼字的所有項目,並將找出的項目組成一個最優的「答案」,使得答案中各項目所包含的碼字長度總和最大。每一個項目包括一個碼字,以及該碼字在文本中的一個覆蓋序列(如』abcadc』就是碼字』abac』的一個覆蓋序列),並且覆蓋序列的長度不超過1000。同時,「答案」要求其中每個項目的覆蓋序列互相沒有重疊。
〖問題分析〗
對於此題,一種較容易得出的基本演算法是:對覆蓋序列在文本中的終止位置進行循環,再判斷包含了哪些碼字,找出所有項目,並最後使用動態規劃的方法將項目組成最優的「答案」。
演算法的其它方面我們暫且不做考慮,而先對問題所採用的邏輯結構進行選擇。
如果我們採用線性的邏輯結構(如循環隊列),那麼我們在判斷是否包含某個碼字t時,所用的方法為:初始時用指針p指向終止位置,接著通過p的不斷前移,依次找出碼字t從尾到頭的各個字母。例如碼字為「ABDCAB」,而文本圖1-1,終止位置為最右邊的箭頭符號,每個箭頭代表依次找到的碼字的各個字母。
指針p的移動方向
A B D C A B
C D A C B D C A D C D B A D C C B A D
圖1-1
由於題目規定碼字的覆蓋序列長度不超過1000,所以進行這樣的一次是否包含的判斷,其復雜度為O(1000)。
由於碼字t中相鄰兩字母在文本中的位置,並非只有相鄰(如圖1-1中的』D』和』C』)這一種關系,中間還可能間隔了許多的字母(如圖1-1中』C』和』A』就間隔了2個字母),而線性結構中擁有的信息,僅僅只存在於相鄰的兩元素之間。通過這樣簡單的信息來尋找碼字的某一個字母,其效率顯然不高。
如果我們建立一個有向圖,其中頂點i(即文本的第i位)用52條弧分別連接』a』..』z』,』A』..』Z』這52個字母在i位以前最後出現的位置(如圖1-2的連接方式),我們要尋找碼字中某個字母的前一個字母,就可以直接利用已連接的邊,而不需用枚舉的方法。我們也可以把問題看為:從有向圖的一個頂點出發,尋找一條長度為length(t)-1的路徑,並且路徑中經過的頂點,按照碼字t中的字母有序。
C D A C B D C A D C D B A D C C B A D
圖1-2
通過計算,用圖進行記錄在空間上完全可以承受(記錄1000個點×52條弧×4位元組的長整型=200k左右)。在時間上,由於可以充分利用第i位和第i+1位弧的連接方式變化不大這一點(如圖1-2所示,第i位和第i+1位只有一條弧的指向發生了變化,即第i+1位將其中一條弧指向了第i位),所以要對圖中的弧進行記錄,只需對弧的指向進行整體賦值,並改變其中的某一條弧即可。
因此,我們通過採用圖的邏輯結構,使得尋找字母的效率大大提高,其判斷的復雜度為O(length(t)),最壞為O(100),比原來方法的判斷效率提高了10倍。
(附程序codes.pas)
對於這個例子,雖然用線性的數據結構也可以解決,但由於判斷的特殊性,每次需要的信息並不能從相鄰的元素中找到,而線性結構中只有相鄰元素之間存在關系的這一點,就成為了一個很明顯的缺點。因此,問題一線性結構中的信息,就屬於「不可直接使用」的信息。相對而言,圖的結構就正好滿足了我們的需要,將所有可能產生關系的點都用弧連接起來,使我們可以利用弧的關系,高效地進行判斷尋找的過程。雖然圖的結構更加復雜,但卻將「不可直接使用」的信息,轉化成為了「可直接使用」的信息,演算法效率的提高,自然在情理之中。。
二、 不記錄「無用」信息。
從問題一中我們看到,由於圖結構的信息量大,所以其中的信息基本上都是「可用」的。但是,這並不表示我們就一定要使用圖的結構。在某些情況下,圖結構中的「可用」信息,是有些多餘的。
信息都「可用」自然是好事,但倘若其中「無用」(不需要)的信息太多,就只會增加我們思考分析和處理問題時的復雜程度,反而不利於我們解決問題了。
〖問題二〗 湖南省1997年組隊賽的《乘船問題》
〖問題描述〗
有N個人需要乘船,而每船最多隻能載兩人,且必須同名或同姓。求最少需要多少條船。
〖問題分析〗
看到這道題,很多人都會想到圖的數據結構:將N個人看作無向圖的N個點,凡同名或同姓的人之間都連上邊。
要滿足用船最少的條件,就是需要盡量多的兩人共乘一條船,表現在圖中就是要用最少的邊完成對所有頂點的覆蓋。這就正好對應了圖論的典型問題:求最小邊的覆蓋。所用的演算法為「求任意圖最大匹配」的演算法。
使用「求任意圖最大匹配」的演算法比較復雜(要用到擴展交錯樹,對花的收縮等等),效率也不是很高。因此,我們必須尋找一個更簡單高效的方法。
首先,由於圖中任兩個連通分量都是相對獨立的,也就是說任一條匹配邊的兩頂點,都只屬於同一個連通分量。因此,我們可以對每個連通分量分別進行處理,而不會影響最終的結果。
同時,我們還可以對需要船隻s的下限進行估計:
對於一個包含Pi個頂點的連通分量,其最小覆蓋邊數顯然為[Pi/2]。若圖中共有L個連通分量,則s=∑[Pi/2](1<=i<=L)。
然後,我們通過多次嘗試,可得出一個猜想:
實際需要的覆蓋邊數完全等於我們求出的下限∑[Pi/2](1<=i<=L)。
要用圖的結構對上述猜想進行證明,可參照以下兩步進行:
1. 連通分量中若不存在度為1的點,就必然存在迴路。
2. 從圖中刪去度為1的點及其相鄰的點,或刪去迴路中的任何一邊,連通分量依然連通,即連通分量必然存在非橋邊。
由於圖的方法不是這里的重點,所以具體證明不做詳述。而由採用圖的數據結構得出的演算法為:每次輸出一條非橋的邊,並從圖中將邊的兩頂點刪去。此演算法的時間復雜度為O(n3)。(尋找一條非橋邊的復雜度為O(n2),尋找覆蓋邊操作的復雜度為O(n))
由於受到圖結構的限制,時間復雜度已經無法降低,所以如果我們要繼續對演算法進行優化,只有考慮使用另一種邏輯結構。這里,我想到了使用二叉樹的結構,具體說就是將圖中的連通分量都轉化為二叉樹,用二叉樹來解決問題。
首先,我們以連通分量中任一個頂點作為樹根,然後我們來確定建樹的方法。
1. 找出與根結點i同姓的點j(j不在二叉樹中)作為i的左兒子,再以j為樹根建立子樹。
2. 找出與根結點i同名的點k(k不在二叉樹中)作為i的右兒子,再以k為樹根建立子樹。
如圖2-1-1中的連通分量,我們通過上面的建樹方法,可以使其成為圖2-1-2中的二叉樹的結構(以結點1為根)。(兩點間用實線表示同姓,虛線表示同名)
圖2-1-2
圖2-1-1
接著,我就來證明這棵樹一定包含了連通分量中的所有頂點。
【引理2.1】
若二叉樹T中包含了某個結點p,那麼連通分量中所有與p同姓的點一定都在T中。
證明:
為了論證的方便,我們約定:s表示與p同姓的頂點集合;lc[p,0]表示結點p,lc[p,i](i>0)表示lc[p,i-1]的左兒子,顯然lc[p,i]與p是同姓的。
假設存在某個點q,滿足qs且qT。由於s是有限集合,因而必然存在某個lc[p,k]無左兒子。則我們可以令lc[p,k+1]=q,所以qT,與假設qT相矛盾。
所以假設不成立,原命題得證。
由引理2.1的證明方法,我們同理可證引理2.2。
【引理2.2】
若二叉樹T中包含了某個結點p,那麼連通分量中所有與p同名的點一定都在T中。
有了上面的兩個引理,我們就不難得出下面的定理了。
【定理一】
以連通分量中的任一點p作為根結點的二叉樹,必然能夠包含連通分量中的所有頂點。
證明:
由引理2.1和引理2.2,所有與p同姓或同名的點都一定在二叉樹中,即連通分量中所有與p有邊相連的點都在二叉樹中。由連通分量中任兩點間都存在路徑的特性,該連通分量中的所有點都在二叉樹中。
在證明二叉樹中包含了連通分量的所有頂點後,我們接著就需要證明我們的猜想,也就是下面的定理:
【定理二】包含m個結點的二叉樹Tm,只需要船的數量為boat[m]=[m/2](mN)。
證明:
(i) 當m=1,m=2,m=3時命題顯然成立。
圖2-2-1
圖2-2-2
圖2-2-3
(ii) 假設當m<k(k>3)時命題成立,那麼當m=k時,我們首先從樹中找到一個層次最深的結點,並假設這個結點的父親為p。那麼,此時有且只有以下三種情況(結點中帶有陰影的是p結點):
(1) 如圖2-2-1,p只有一個兒子。此時刪去p和p唯一的兒子,Tk就成為了Tk-2,則boat[k]=boat[k-2]+1=[(k-2)/2]+1=[k/2]。
(2) 如圖2-2-2,p有兩個兒子,並且p是其父親的左兒子。此時可刪去p和p的右兒子,並可將p的左兒子放到p的位置上。同樣地,Tk成為了Tk-2,boat[k]=boat[k-2]+1=[k/2]。
(3) 如圖2-2-3,p有兩個兒子,並且p是其父親的右兒子。此時可刪去p和p的左兒子,並可將p的右兒子放到p的位置上。情況與(2)十分相似,易得此時得boat[k]=boat[k-2]+1=[k/2]。
綜合(1)、(2)、(3),當m=k時,boat[k]=[k/2]。
最後,綜合(i)、(ii),對於一切mN,boat[m]=[m/2]。
由上述證明,我們將問題中數據的圖結構轉化為樹結構後,可以得出求一棵二叉樹的乘船方案的演算法:
proc try(father:integer;var root:integer;var rest:byte);
{輸出root為樹根的子樹的乘船方案,father=0表示root是其父親的左兒子,
father=1表示root是其父親的右兒子,rest表示輸出子樹的乘船方案後,
是否還剩下一個根結點未乘船}
begin
visit[root]:=true; {標記root已訪問}
找到一個與root同姓且未訪問的結點j;
if j<>n+1 then try(0,j,lrest);
找到一個與root同姓且未訪問的結點k;
if k<>n+1 then try(1,k,rrest);
if (lrest=1) xor (rrest=1) then begin {判斷root是否只有一個兒子,情況一}
if lrest=1 then print(lrest,root) else print(rrest,root);
rest:=0;
end
else if (lrest=1) and (rrest=1) then begin {判斷root是否有兩個兒子}
if father=0 then begin
print(rrest,root);root:=j; {情況二}
end
else begin
print(lrest,root);root:=k; {情況三}
end;
rest:=1;
end
else rest:=1;
end;
這只是輸出一棵二叉樹的乘船方案的演算法,要輸出所有人的乘船方案,我們還需再加一層循環,用於尋找各棵二叉樹的根結點,但由於每個點都只會訪問一次,尋找其左右兒子各需進行一次循環,所以演算法的時間復雜度為O(n2)。(附程序boat.pas)
最後,我們對兩種結構得出不同時間復雜度演算法的原因進行分析。其中最關鍵的一點就是因為二叉樹雖然結構相對較簡單,但已經包含了幾乎全部都「有用」的信息。由我們尋找乘船方案的演算法可知,二叉樹中的所有邊不僅都發揮了作用,而且沒有重復的使用,可見信息的利用率也是相當之高的。
既然採用樹結構已經足夠,圖結構中的一些信息就顯然就成為了「無用」的信息。這些多餘的「無用」信息,使我們在分析問題時難於發現規律,也很難找到高效的演算法進行解決。這正如迷宮中的牆一樣,越多越難走。「無用」的信息,只會干擾問題的規律性,使我們更難找出解決問題的方法。
小結
我們對數據的邏輯結構進行選擇,是構造數學模型一大關鍵,而演算法又是用來解決數學模型的。要使演算法效率高,首先必須選好數據的邏輯結構。上面已經提出了選擇邏輯結構的兩個條件(思考方向),總之目的是提高信息的利用效果。利用「可直接使用」的信息,由於中間不需其它操作,利用的效率自然很高;不不記錄「無用」的信息,就會使我們更加專心地研究分析「有用」的信息,對信息的使用也必然會更加優化。
總之,在解決問題的過程中,選擇合理的邏輯結構是相當重要的環
三、 選擇合理的存儲結構
數據的存儲結構,分為順序存儲結構和鏈式存儲結構。順序存儲結構的特點是藉助元素在存儲器中的相對位置來表示數據元素之間的邏輯關系;鏈式存儲結構則是藉助指示元素存儲地址的指針表示數據元素之間的邏輯關系。
因為兩種存儲結構的不同,導致這兩種存儲結構在具體使用時也分別存在著優點和缺點。
這里有一個較簡單的例子:我們需要記錄一個n×n的矩陣,矩陣中包含的非0元素為m個。
此時,我們若採用順序存儲結構,就會使用一個n×n的二維數組,將所有數據元素全部記錄下來;若採用鏈式存儲結構,則需要使用一個包含m個結點的鏈表,記錄所有非0的m個數據元素。由這樣兩種不同的記錄方式,我們可以通過對數據的不同操作來分析它們的優點和缺點。
1. 隨機訪問矩陣中任意元素。由於順序結構在物理位置上是相鄰的,所以可以很容易地獲得任意元素的存儲地址,其復雜度為O(1);對於鏈式結構,由於不具備物理位置相鄰的特點,所以首先必須對整個鏈表進行一次遍歷,尋找需進行訪問的元素的存儲地址,其復雜度為O(m)。此時使用順序結構顯然效率更高。
2. 對所有數據進行遍歷。兩種存儲結構對於這種操作的復雜度是顯而易見的,順序結構的復雜度為O(n2),鏈式結構為O(m)。由於在一般情況下m要遠小於n2,所以此時鏈式結構的效率要高上許多。
除上述兩種操作外,對於其它的操作,這兩種結構都不存在很明顯的優點和缺點,如對鏈表進行刪除或插入操作,在順序結構中可表示為改變相應位置的數據元素。
既然兩種存儲結構對於不同的操作,其效率存在較大的差異,那麼我們在確定存儲結構時,必須仔細分析演算法中操作的需要,合理地選擇一種能夠「揚長避短」的存儲結構。
一、合理採用順序存儲結構。
我們在平常做題時,大多都是使用順序存儲結構對數據進行存儲。究其原因,一方面是出於順序結構操作方便的考慮,另一方面是在程序實現的過程中,使用順序結構相對於鏈式結構更便於對程序進行調試和查找錯誤。因此,大多數人習慣上認為,能夠使用順序結構進行存儲的問題,最「好」採用順序存儲結構。
其實,這個所謂的「好」只是一個相對的標准,是建立在以下兩個前提條件之下的:
1. 鏈式結構存儲的結點與順序結構存儲的結點數目相差不大。這種情況下,由於存儲的結點數目比較接近,使用鏈式結構完全不能體現出記錄結點少的優點,並且可能會由於指針操作較慢而降低演算法的效率。更有甚者,由於指針自身佔用的空間較大,且結點數目較多,因而演算法對空間的要求可能根本無法得到滿足。
2. 並非演算法效率的瓶頸所在。由於不是演算法最費時間的地方,這里是否進行改進,顯然是不會對整個演算法構成太大影響的,若使用鏈式結構反而會顯得操作過於繁瑣。
二、必要時採用鏈式存儲結構。
上面我對使用順序存儲結構的條件進行了分析,最後就只剩下何時應該採用鏈式存儲結構的問題了。
由於鏈式結構中指針操作確實較繁瑣,並且速度也較慢,調試也不方便,因而大家一般都不太願意用鏈式的存儲結構。但是,這只是一般的觀點,當鏈式結構確實對演算法有很大改進時,我們還是不得不進行考慮的。
〖問題三〗 IOI99的《地下城市》。
〖問題描述〗
已知一個城市的地圖,但未給出你的初始位置。你需要通過一系列的移動和探索,以確定初始時所在的位置。題目的限制是:
1. 不能移動到有牆的方格。
2. 只能探索當前所在位置四個方向上的相鄰方格。
在這兩個限制條件下,要求我們的探索次數(不包括移動)盡可能的少。
〖問題分析〗
由於存儲結構要由演算法的需要確定,因此我們首先來確定問題的演算法。
經過對問題的分析,我們得出解題的基本思想:先假設所有無牆的方格都可能是初始位置,再通過探索一步步地縮小初始位置的范圍,最終得到真正的初始位置。同時,為提高演算法效率,我們還用到了分治的思想,使我們每一次探索都盡量多的縮小初始位置的范圍(使程序盡量減少對運氣的依賴)。
接著,我們來確定此題的存儲結構。
由於這道題的地圖是一個二維的矩陣,所以一般來講,採用順序存儲結構理所當然。但是,順序存儲結構在這道題中暴露了很大的缺點。我們所進行的最多的操作,一是對初始位置的范圍進行篩選,二是判斷要選擇哪個位置進行探索。而這兩種操作,所需要用到的數據,只是龐大地圖中很少的一部分。如果採用順序存儲結構(如圖3-1中陰影部分表示已標記),無論你需要用到多少數據,始終都要完全的遍歷整個地圖。
4
3
2
1
1 2 3 4
圖3-1
head
圖3-2
然而,如果我們採用的是鏈式存儲結構(如圖3-2的鏈表),那麼我們需要多少數據,就只會遍歷多少數據,這樣不僅充分發揮了鏈式存儲結構的優點,而且由於不需單獨對某一個數據進行提取,每次都是對所有數據進行判斷,從而避免了鏈式結構的最大缺點。
我們使用鏈式存儲結構,雖然沒有降低問題的時間復雜度(鏈式存儲結構在最壞情況下的存儲量與順序存儲結構的存儲量幾乎相同),但由於體現了前文所述選擇存儲結構時揚長避短的原則,因而演算法的效率也大為提高。(程序對不同數據的運行時間見表3-3)
測試數據編號 使用順序存儲結構的程序 使用鏈式存儲結構的程序
1 0.06s 0.02s
2 1.73s 0.07s
3 1.14s 0.06s
4 3.86s 0.14s
5 32.84s 0.21s
6 141.16s 0.23s
7 0.91s 0.12s
8 6.92s 0.29s
9 6.10s 0.23s
10 17.41s 0.20s
表3-3
(附使用鏈式存儲結構的程序under.pas)
我們選擇鏈式的存儲結構,雖然操作上可能稍復雜一些,但由於改進了演算法的瓶頸,演算法的效率自然也今非昔比。由此可見,必要時選擇鏈式結構這一方法,其效果是不容忽視的。
小結
合理選擇邏輯結構,由於牽涉建立數學模型的問題,可能大家都會比較注意。但是對存儲結構的選擇,由於不會對演算法復雜度構成影響,所以比較容易忽視。那麼,這種不能降低演算法復雜度的方法是否需要重視呢?
大家都知道,剪枝作為一種常用的優化演算法的方法,被廣泛地使用,但剪枝同樣是無法改變演算法的復雜度的。因此,作用與剪枝相似的存儲結構的合理選擇,也是同樣很值得重視的。
總之,我們在設計演算法的過程中,必須充分考慮存儲結構所帶來的不同影響,選擇最合理的存儲結構。
四、 多種數據結構相結合
上文所探討的,都是如何對數據結構進行選擇,其中包含了邏輯結構的選擇和存儲結構的選擇,是一種具有較大普遍性的演算法優化方法。對於多數的問題,我們都可以通過選擇一種合理的邏輯結構和存儲結構以達到優化演算法的目的。
但是,有些問題卻往往不如人願,要對這類問題的數據結構進行選擇,常常會顧此失彼,有時甚至根本就不存在某一種合適的數據結構。此時,我們是無法選擇出某一種合適的數據結構的,以上的方法就有些不太適用了。
為解決數據結構難以選擇的問題,我們可以採用將多種數據結構進行結合的方法。通過多種數據結構相結合,達到取長補短的作用,使不同的數據結構在演算法中發揮出各自的優勢。
這只是我們將多種數據結構進行結合的總思想,具體如何進行結合,我們可以先看下面的例子。
我們可以採用映射的方法,將線性結構中的元素與堆中間的結點一一對應起來,若線性的數組中的元素發生變化,堆中相應的結點也接著變化,堆中的結點發生變化,數組中相應的元素也跟著變化。
將兩種結構進行結合後,無論是第一步還是第二步,我們都不需對所有元素進行遍歷,只需進行常數次復雜度為O(log2n)的堆化操作。這樣,整個時間復雜度就成為了O(nlog2n),演算法效率無疑得到了很大提高。
五、 總結
我們平常使用數據結構,往往只將其作為建立模型和演算法實現的工具,而沒有考慮這種工具對程序效率所產生的影響。信息學問題隨著難度的不斷增大,對演算法時空效率的要求也越來越高,而演算法的時空效率,在很大程度上都受到了數據結構的制約。
❽ 藍胖子機器智能:核心演算法促物流提效丨強鏈補鏈在行動
手指輕輕一動、滑鼠輕輕一點,快遞就能准時送貨上門。不少人都在感嘆:「現在的快遞真方便!」確實,不管是要求「鮮、快、優」的生鮮產品,還是需要精準溫控的各種葯物,抑或是「大塊頭」的家電傢具和工業配件,都成了快遞運輸的主要品種。在電商行業迅速發展的當下,物流行業的自動化與智能化已經成為必然。
核心演算法讓物流環節更高效
現階段,物流行業發展迅速,在自動化與智能化方面有很大的優化空間。在嗅到其中的市場機會後,不少公司瞄準了這一賽道,對智能物流領域進行布局。
在將機器人、人工智慧技術與實際物流環節相結合的過程中,演算法是其中繞不開的關鍵詞。目前,藍胖子在演算法方面的布局有四大方向。
第一個方向是計算機視覺。換句話說,就是讓機器人的眼睛能夠識別不同物品,尤其是在物品重疊時候的分割。
第二個方向是機械臂的控制和運動規劃。針對這點,張羽雪也給出了進一步解釋。「比如我已經識別到某個包裹了,我要把它從a點抓到b點。」她說,「這個三維空間里其實是有無數條運動軌跡的,我們要找到最快、最短的這一條路徑,這就是運動規劃。」
第三個方向是移動和多機協作。移動機器人在給定的區域里自主移動、自主導航、自主避障、自主充電。「如果我有10台、20台、50台甚至100台移動機器人,我應該怎麼調動每一台機器人,使它們在運作過程中不會相互碰撞?當一台機器人在運作的時候,如何縮短另一台機器人的等待時間?這就需要多機調度技術。」張羽雪說。
第四個就是人工智慧技術的應用。在遇到新場景後,機器人需要通過深度學習進行視覺訓練,以快速識別新的場景。裝箱的規劃也是人工智慧技術的應用之一。「這裡面(裝箱)用到了時空優化技術,就是去優化裝箱,讓所用的時間最少,所用的空間最大。」張羽雪表示。
技術與物流業務需要緊密結合
機器視覺、深度學習等技術應用需要積累大量的數據,也需要較多的試錯過程。這個過程的成本很高,對包括藍胖子在內的所有人工智慧企業都提出了不小的挑戰。
在張羽雪看來,應對此類挑戰的方法主要有兩個,一方面需要算力的提升、海量的數據以及更快的通信,另一方面就是需要技術與業務的緊密結合。
從第一個方面來看,算力的提升與整個行業底層技術的提高息息相關,數據的獲取則離不開企業與客戶的相互合作。客戶提供的數據能夠訓練和測試演算法。張羽雪表示,「客戶的數據對演算法的積累和機器人的訓練會起到很好的作用。」
通信速度的提升對機器人的應用也有著極大助力。當前,5G的使用讓機器人計算的速度更快,數據傳輸更快,延時更低,協作更高效。
事實上,機器人的控制系統與客戶的各個數據系統,包括ERP(企業資源計劃)系統、倉儲管理系統和生產規劃系統的連接與打通其實是非常難的一點。在實驗室裡面,很多技術問題都是可以解決的,但並不是所有的技術都能解決業務問題。
張羽雪還呼籲市場應該多給智能機器人行業一些成長的時間。智能機器人的技術積累需要一定時間,從技術到應用需要不斷地進行試錯,還要在各種場景中不斷地訓練機器人,使機器人達到更高的作業精度和准確度。在這點上,政府引導基金和民間資本都需要給科創企業更多的時間和更大力度的支持,傳統企業也需要逐步轉變思維,將目光放長遠,採用新興技術來解決當前以及未來的挑戰。
生態的構建對每個行業的發展都非常關鍵。張羽雪認為,政府是構建生態的一大主體,通過發揮主導作用,政府能夠建立本地的相關企業集群。此外,德勤、凱捷等IT服務及咨詢公司是連接新興企業與傳統大企業的橋梁,將大客戶的需求與新型企業的技術充分對接,也是構建產業生態的一大力量「如果某個大客戶有需求,咨詢公司就去尋找哪一個初創企業可以提供給他們相應的技術,為客戶設計一個整體解決方案。」張羽雪說,「很多大企業已經開始在搭建這樣的AI生態了,這也是未來產業的發展趨勢。」
編輯丨趙晨
美編丨馬利亞
❾ pascal題目
2003年國家集訓隊論文,王知昆,淺談用極大化思想解決最大子矩形問題
網上有的,O(n²)的復雜度,n,m是5000都能1秒出解
淺談用極大化思想解決最大子矩形問題
福州第三中學 王知昆
【摘要】
本文針對一類近期經常出現的有關最大(或最優)子矩形及相關變形問題,介紹了極大化思想在這類問題中的應用。分析了兩個具有一定通用性的演算法。並通過一些例題講述了這些演算法選擇和使用時的一些技巧。
【關鍵字】 矩形,障礙點,極大子矩形
【正文】
一、 問題
最大子矩形問題:在一個給定的矩形網格中有一些障礙點,要找出網格內部不包含任何障礙點,且邊界與坐標軸平行的最大子矩形。
這是近期經常出現的問題,例如冬令營2002的《奶牛浴場》,就屬於最大子矩形問題。
Winter Camp2002,奶牛浴場
題意簡述:(原題見論文附件)
John要在矩形牛場中建造一個大型浴場,但是這個大型浴場不能包含任何一個奶牛的產奶點,但產奶點可以出在浴場的邊界上。John的牛場和規劃的浴場都是矩形,浴場要完全位於牛場之內,並且浴場的輪廓要與牛場的輪廓平行或者重合。要求所求浴場的面積盡可能大。
參數約定:產奶點的個數S不超過5000,牛場的范圍N×M不超過30000×30000。
二、 定義和說明
首先明確一些概念。
1、 定義有效子矩形為內部不包含任何障礙點且邊界與坐標軸平行的子矩形。如圖所示,第一個是有效子矩形(盡管邊界上有障礙點),第二個不是有效子矩形(因為內部含有障礙點)。
2、 極大有效子矩形:一個有效子矩形,如果不存在包含它且比它大的有效子矩形,就稱這個有效子矩形為極大有效子矩形。(為了敘述方便,以下稱為極大子矩形)
3、 定義最大有效子矩形為所有有效子矩形中最大的一個(或多個)。以下簡稱為最大子矩形。
三、 極大化思想
【定理1】在一個有障礙點的矩形中的最大子矩形一定是一個極大子矩形。
證明:如果最大子矩形A不是一個極大子矩形,那麼根據極大子矩形的定義,存在一個包含A且比A更大的有效子矩形,這與「A是最大子矩形」矛盾,所以【定理1】成立。
四、 從問題的特徵入手,得到兩種常用的演算法
定理1雖然很顯然,但卻是很重要的。根據定理1,我們可以得到這樣一個解題思路:通過枚舉所有的極大子矩形,就可以找到最大子矩形。下面根據這個思路來設計演算法。
約定:為了敘述方便,設整個矩形的大小為n×m,其中障礙點個數為s。
演算法1
演算法的思路是通過枚舉所有的極大子矩形找出最大子矩形。根據這個思路可以發現,如果演算法中有一次枚舉的子矩形不是有效子矩形、或者不是極大子矩形,那麼可以肯定這個演算法做了「無用功」,這也就是需要優化的地方。怎樣保證每次枚舉的都是極大子矩形呢,我們先從極大子矩形的特徵入手。
【定理2】:一個極大子矩形的四條邊一定都不能向外擴展。更進一步地說,一個有效子矩形是極大子矩形的充要條件是這個子矩形的每條邊要麼覆蓋了一個障礙點,要麼與整個矩形的邊界重合。
定理2的正確性很顯然,如果一個有效子矩形的某一條邊既沒有覆蓋一個障礙點,又沒有與整個矩形的邊界重合,那麼肯定存在一個包含它的有效子矩形。根據定理2,我們可以得到一個枚舉極大子矩形的演算法。為了處理方便,首先在障礙點的集合中加上整個矩形四角上的點。每次枚舉子矩形的上下左右邊界(枚舉覆蓋的障礙點),然後判斷是否合法(內部是否有包含障礙點)。這樣的演算法時間復雜度為O(S5),顯然太高了。考慮到極大子矩形不能包含障礙點,因此這樣枚舉4個邊界顯然會產生大量的無效子矩形。
考慮只枚舉左右邊界的情況。對於已經確定的左右邊界,可以將所有處在這個邊界內的點按從上到下排序,如圖1中所示,每一格就代表一個有效子矩形。這樣做時間復雜度為O(S3)。由於確保每次得到的矩形都是合法的,所以枚舉量比前一種演算法小了很多。但需要注意的是,這樣做枚舉的子矩形雖然是合法的,然而不一定是極大的。所以這個演算法還有優化的餘地。通過對這個演算法不足之處的優化,我們可以得到一個高效的演算法。
回顧上面的演算法,我們不難發現,所枚舉的矩形的上下邊界都覆蓋了障礙點或者與整個矩形的邊界重合,問題就在於左右邊界上。只有那些左右邊界也覆蓋了障礙點或者與整個矩形的邊界重合的有效子矩形才是我們需要考察的極大子矩形,所以前面的演算法做了不少「無用功」。怎麼減少「無用功」呢,這里介紹一種演算法(演算法1),它可以用在不少此類題目上。
演算法的思路是這樣的,先枚舉極大子矩形的左邊界,然後從左到右依次掃描每一個障礙點,並不斷修改可行的上下邊界,從而枚舉出所有以這個定點為左邊界的極大子矩形。考慮如圖2中的三個點,現在我們要確定所有以1號點為左邊界的極大矩形。先將1號點右邊的點按橫坐標排序。然後按從左到右的順序依次掃描1號點右邊的點,同時記錄下當前的可行的上下邊界。
開始時令當前的上下邊界分別為整個矩形的上下邊界。然後開始掃描。第一次遇到2號點,以2號點作為右邊界,結合當前的上下邊界,就得到一個極大子矩形(如圖3)。同時,由於所求矩形不能包含2號點,且2號點在1號點的下方,所以需要修改當前的下邊界,即以2號點的縱坐標作為新的下邊界。第二次遇到3號點,這時以3號點的橫坐標作為右邊界又可以得到一個滿足性質1的矩形(如圖4)。類似的,需要相應地修改上邊界。以此類推,如果這個點是在當前點(確定左邊界的點)上方,則修改上邊界;如果在下方,則修改下邊界;如果處在同一行,則可中止搜索(因為後面的矩形面積都是0了)。由於已經在障礙點集合中增加了整個矩形右上角和右下角的兩個點,所以不會遺漏右邊界與整個矩形的右邊重合的極大子矩形(如圖5)。需要注意的是,如果掃描到的點不在當前的上下邊界內,那麼就不需要對這個點進行處理。
這樣做是否將所有的極大子矩形都枚舉過了呢?可以發現,這樣做只考慮到了左邊界覆蓋一個點的矩形,因此我們還需要枚舉左邊界與整個矩形的左邊界重合的情況。這還可以分為兩類情況。一種是左邊界與整個舉行的左邊界重合,而右邊界覆蓋了一個障礙點的情況,對於這種情況,可以用類似的方法從右到左掃描每一個點作為右邊界的情況。另一種是左右邊界均與整個矩形的左右邊界重合的情況,對於這類情況我們可以在預處理中完成:先將所有點按縱坐標排序,然後可以得到以相鄰兩個點的縱坐標為上下邊界,左右邊界與整個矩形的左右邊界重合的矩形,顯然這樣的矩形也是極大子矩形,因此也需要被枚舉到。
通過前面兩步,可以枚舉出所有的極大子矩形。演算法1的時間復雜度是O(S2)。這樣,可以解決大多數最大子矩形和相關問題了。
雖然以上的演算法(演算法1)看起來是比較高效的,但也有使用的局限性。可以發現,這個演算法的復雜度只與障礙點的個數s有關。但對於某些問題,s最大有可能達到n×m,當s較大時,這個演算法就未必能滿足時間上的要求了。能否設計出一種依賴於n和m的演算法呢?這樣在演算法1不能奏效的時候我們還有別的選擇。我們再重新從最基本的問題開始研究。
演算法2
首先,根據定理1:最大有效子矩形一定是一個極大子矩形。不過與前一種演算法不同的是,我們不再要求每一次枚舉的一定是極大子矩形而只要求所有的極大子矩形都被枚舉到。看起來這種演算法可能比前一種差,其實不然,因為前一種演算法並不是完美的:雖然每次考察的都是極大子矩形,但它還是做了一定量的「無用功」。可以發現,當障礙點很密集的時候,前一種演算法會做大量沒用的比較工作。要解決這個問題,我們必須跳出前面的思路,重新考慮一個新的演算法。注意到極大子矩形的個數不會超過矩形內單位方格的個數,因此我們有可能找出一種時間復雜度是O(N×M)的演算法。
定義:
有效豎線:除了兩個端點外,不覆蓋任何障礙點的豎直線段。
懸線:上端點覆蓋了一個障礙點或達到整個矩形上端的有效豎線。如圖所示的三個有效豎線都是懸線。
對於任何一個極大子矩形,它的上邊界上要麼有一個障礙點,要麼和整個矩形的上邊界重合。那麼如果把一個極大子矩形按x坐標不同切割成多個(實際上是無數個)與y軸垂直的線段,則其中一定存在一條懸線。而且一條懸線通過盡可能地向左右移動恰好能得到一個子矩形(未必是極大子矩形,但只可能向下擴展)。通過以上的分析,我們可以得到一個重要的定理。
【定理3】:如果將一個懸線向左右兩個方向盡可能移動所得到的有效子矩形稱為這個懸線所對應的子矩形,那麼所有懸線所對應的有效子矩形的集合一定包含了所有極大子矩形的集合。
定理3中的「盡可能」移動指的是移動到一個障礙點或者矩形邊界的位置。
根據【定理3】可以發現,通過枚舉所有的懸線,就可以枚舉出所有的極大子矩形。由於每個懸線都與它底部的那個點一一對應,所以懸線的個數=(n-1)×m(以矩形中除了頂部的點以外的每個點為底部,都可以得到一個懸線,且沒有遺漏)。如果能做到對每個懸線的操作時間都為O(1),那麼整個演算法的復雜度就是O(NM)。這樣,我們看到了解決問題的希望。
現在的問題是,怎樣在O(1)的時間內完成對每個懸線的操作。我們知道,每個極大子矩形都可以通過一個懸線左右平移得到。所以,對於每個確定了底部的懸線,我們需要知道有關於它的三個量:頂部、左右最多能移動到的位置。對於底部為(i,j)的懸線,設它的高為hight[i,j],左右最多能移動到的位置為left[i,j],right[i,j]。為了充分利用以前得到的信息,我們將這三個函數用遞推的形式給出。
對於以點(i,j)為底部的懸線:
如果點(i-1,j)為障礙點,那麼,顯然以(i,j)為底的懸線高度為1,而且左右均可以移動到整個矩形的左右邊界,即
如果點(i-1,j)不是障礙點,那麼,以(i,j)為底的懸線就等於以(i-1,j)為底的懸線+點(i,j)到點(i-1,j)的線段。因此,height[i,j]=height[i-1,j]+1。比較麻煩的是左右邊界,先考慮left[i,j]。如下圖所示,(i,j)對應的懸線左右能移動的位置要在(i-1,j)的基礎上變化。
即left[i,j]=max
right[i,j]的求法類似。綜合起來,可以得到這三個參數的遞推式:
這樣做充分利用了以前得到的信息,使每個懸線的處理時間復雜度為O(1)。對於以點(i,j)為底的懸線對應的子矩形,它的面積為(right[i,j]-left[i,j])*height[i,j]。
這樣最後問題的解就是:
Result=
max
整個演算法的時間復雜度為O(NM),空間復雜度是O(NM)。
兩個演算法的對比:
以上說了兩種具有一定通用性的處理演算法,時間復雜度分別為O(S2)和O(NM)。兩種演算法分別適用於不同的情況。從時間復雜度上來看,第一種演算法對於障礙點稀疏的情況比較有效,第二種演算法則與障礙點個數的多少沒有直接的關系(當然,障礙點較少時可以通過對障礙點坐標的離散化來減小處理矩形的面積,不過這樣比較麻煩,不如第一種演算法好),適用於障礙點密集的情況。
五、 例題
將前面提出的兩種演算法運用於具體的問題。
1、 Winter Camp2002,奶牛浴場
分析:
題目的數學模型就是給出一個矩形和矩形中的一些障礙點,要求出矩形內的最大有效子矩形。這正是我們前面所討論的最大子矩形問題,因此前兩種演算法都適用於這個問題。
下面分析兩種演算法運用在本題上的優略:
對於第一種演算法,不用加任何的修改就可以直接應用在這道題上,時間復雜度為O(S2),S為障礙點個數;空間復雜度為O(S)。
對於第二種演算法,需要先做一定的預處理。由於第二種演算法復雜度與牛場的面積有關,而題目中牛場的面積很大(30000×30000),因此需要對數據進行離散化處理。離散化後矩形的大小降為S×S,所以時間復雜度為O(S2),空間復雜度為O(S)。說明:需要注意的是,為了保證演算法能正確執行,在離散化的時候需要加上S個點,因此實際需要的時間和空間較大,而且編程較復雜。
從以上的分析來看,無論從時空效率還是編程復雜度的角度來看,這道題採用第一種演算法都更優秀。
2、 OIBH模擬賽1,提高組,Candy
題意簡述:(原題見論文附件)
一個被分為 n*m 個格子的糖果盒,第 i 行第 j 列位置的格子裡面有 a [i,j] 顆糖。但糖果盒的一些格子被老鼠洗劫。現在需要盡快從這個糖果盒裡面切割出一個矩形糖果盒,新的糖果盒不能有洞,並且希望保留在新糖果盒內的糖的總數盡量多。
參數約定:1 ≤ n,m ≤ 1000
分析
首先需要注意的是:本題的模型是一個矩陣,而不是矩形。在矩陣的情況下,由於點的個數是有限的,所以又產生了一個新的問題:最大權值子矩陣。
定義:
有效子矩陣為內部不包含任何障礙點的子矩形。與有效子矩形不同,有效子矩陣地邊界上也不能包含障礙點。
有效子矩陣的權值(只有有效子矩形才有權值)為這個子矩陣包含的所有點的權值和。
最大權值有效子矩陣為所有有效子矩陣中權值最大的一個。以下簡稱為最大權值子矩陣。
本題的數學模型就是正權值條件下的最大權值子矩陣問題。再一次利用極大化思想,因為矩陣中的權值都是正的,所以最大權值子矩陣一定是一個極大子矩陣。所以我們只需要枚舉所有的極大子矩陣,就能從中找到最大權值子矩陣。同樣,兩種演算法只需稍加修改就可以解決本題。下面分析兩種演算法應用在本題上的優略:
對於第一種演算法,由於矩形中障礙點的個數是不確定的,而且最大有可能達到N×M,這樣時間復雜度有可能達到O(N2M2),空間復雜度為O(NM)。此外,由於矩形與矩陣的不同,所以在處理上會有一些小麻煩。
對於第二種演算法,稍加變換就可以直接使用,時間復雜度為O(NM),空間復雜度為O(NM)。
可以看出,第一種演算法並不適合這道題,因此最好還是採用第二種演算法。
3、 Usaco Training, Section 1.5.4, Big Barn
題意簡述(原題見論文附件)
Farmer John想在他的正方形農場上建一個正方形谷倉。由於農場上有一些樹,而且Farmer John又不想砍這些樹,因此要找出最大的一個不包含任何樹的一塊正方形場地。每棵樹都可以看成一個點。
參數約定:牛場為N×N的,樹的棵數為T。N≤1000,T≤10000。
分析:
這題是矩形上的問題,但要求的是最大子正方形。首先,明確一些概念。
1、 定義有效子正方形為內部不包含任何障礙點的子正方形
2、 定義極大有效子正方形為不能再向外擴展的有效子正方形,一下簡稱極大子正方形
3、 定義最大有效子正方形為所有有效子正方形中最大的一個(或多個),以下簡稱最大子正方形。
本題的模型有一些特殊,要在一個含有一些障礙點的矩形中求最大子正方形。這與前兩題的模型是否有相似之處呢?還是從最大子正方形的本質開始分析。
與前面的情況類似,利用極大化思想,我們可以得到一個定理:
【定理4】:在一個有障礙點的矩形中的最大有效子正方形一定是一個極大有效子正方形。
根據【定理4】,我們只需要枚舉出所有的極大子正方形,就可以從中找出最大子正方形。極大子正方形有什麼特徵呢?所謂極大,就是不能再向外擴展。如果是極大子矩形,那麼不能再向外擴展的充要條件是四條邊上都覆蓋了障礙點(【定理2】)。類似的,我們可以知道,一個有效子正方形是極大子正方形的充要條件是它任何兩條相鄰的邊上都覆蓋了至少一個障礙點。根據這一點,可以得到一個重要的定理。
【定理5】:每一個極大子正方形都至少被一個極大子矩形包含。且這個極大子正方形一定有兩條不相鄰的邊與這個包含它的極大子矩形的邊重合。
根據【定理5】,我們只需要枚舉所有的極大子矩形,並檢查它所包含的極大子正方形(一個極大子矩形包含的極大子正方形都是一樣大的)是否是最大的就可以了。這樣,問題的實質和前面所說的最大子矩形問題是一樣的,同樣的,所採用的演算法也是一樣的。
因為演算法1和演算法2都枚舉出了所有的極大子矩形,因此,演算法1和演算法2都可以用在本題上。具體的處理方法如下:對於每一個枚舉出的極大子矩形,如圖所示,如果它的邊長為a、b,那麼它包含的極大子正方形的邊長即為min(a,b)。
考慮到N和T的大小不同,所以不同的演算法會有不同的效果。下面分析兩種演算法應用在本題上的優略。
對於第一種演算法,時間復雜度為O(T2),對於第二種演算法,時間復雜度為O(N2)。因為N<T,所以從時間復雜度的角度看,第二種演算法要比第一種演算法好。考慮到兩個演算法的空間復雜度都可以承受,所以選擇第二種演算法較好些。
以下是第一種和第二種演算法編程實現後在USACO Training Program Gateway上的運行時間。可以看出,在數據較大時,演算法2的效率比演算法1高。
演算法1:
Test 1: 0.009375
Test 2: 0.009375
Test 3: 0.009375
Test 4: 0.009375
Test 5: 0.009375
Test 6: 0.009375
Test 7: 0.021875
Test 8: 0.025
Test 9: 0.084375
Test 10: 0.3875
Test 11: 0.525
Test 12: 0.5625
Test 13: 0.690625
Test 14: 0.71875
Test 15: 0.75 演算法2:
Test 1: 0.009375
Test 2: 0.009375
Test 3: 0.009375
Test 4: 0.009375
Test 5: 0.009375
Test 6: 0.00625
Test 7: 0.009375
Test 8: 0.009375
Test 9: 0.0125
Test 10: 0.021875
Test 11: 0.028125
Test 12: 0.03125
Test 13: 0.03125
Test 14: 0.03125
Test 15: 0.034375
以上,利用極大化思想和前面設計的兩個演算法,通過轉換模型,解決了三個具有一定代表性的例題。解題的關鍵就是如何利用極大化思想進行模型轉換和如何選擇演算法。
五、小結
設計演算法要從問題的基本特徵入手,找出解題的突破口。本文介紹了兩種適用於大部分最大子矩形問題及相關變型問題的演算法,它們設計的突破口就是利用了極大化思想,找到了枚舉極大子矩形這種方法。
在效率上,兩種演算法對於不同的情況各有千秋。一個是針對障礙點來設計的,因此復雜度與障礙點有關;另一個是針對整個矩形來設計的,因此復雜度與矩形的面積有關。雖然兩個演算法看起來有著巨大的差別,但他們的本質是相通的,都是利用極大化思想,從枚舉所有的極大有效子矩形入手,找出解決問題的方法。
需要注意的是,在解決實際問題是僅靠套用一些現有演算法是不夠的,還需要對問題進行全面、透徹的分析,找出解題的突破口。
此外,如果採用極大化思想,前面提到的兩種演算法的復雜度已經不能再降低了,因為極大有效子矩形的個數就是O(NM)或O(S2)的。如果採用其他演算法,理論上是有可能進一步提高演算法效率,降低復雜度的。
七、 附錄:
1、幾個例題的原題。 見論文附件.doc
2、例題的程序。 見論文附件.doc
說明:所有程序均在Free Pascal IDE for Dos, Version 0.9.2上編譯運行
參考書目
1、 信息學奧林匹克 競賽指導
----1997~1998競賽試題解析
吳文虎 王建德 著
2、 IOI99中國集訓隊優秀論文集
3、 信息學奧林匹克(季刊)
4、 《金牌之路 競賽輔導》
江文哉主編 陝西師范大學出版社出版