USING INDUCTION TO DESIGN 使用歸納法設計演算法 [4/14]

來源:互聯網
上載者:User

接上文:http://blog.csdn.net/jj12345jj198999/article/details/6604842

 

但是如果1被排除了,那麼2也會因為同樣的原因被刪去。但是,這樣得到的結果集不是最大的,因為我們很容易就能看到可以只刪去2即可。這個問題其實是讓我們去找到一種通用的方法來決定集合中包含哪些元素而已。

使用歸納法求解的思想集中在縮減問題的規模上,這種方法使用起來也很靈活。我們可以通過尋找一個要麼屬於S中的元素或要麼不屬於S中的元素來縮減問題規模。我們將在後面進行這一操作。我們先使用簡潔明了的歸納假設:

歸納假設:我們已經知道如何去解決一個含n-1個元素集合的問題。

最基本的情況很簡單:如果集合中只含有一個元素,集合必須映射到自身,這就是一個一一映射。假設我們已經有了一個含有n個元素的集合A,現在我們尋找一個滿足問題條件的子集S。很顯然找到一個不屬於S集合的元素要比找到一個包含在S集合中元素簡單。我們可以認為任何一個元素i如果沒有被其他元素映射,那麼i不可能包含在S中。(換句話說,在圖右側的元素i,如果沒有一條邊與之相連,那麼i不可能在S中)否則的話,如果i∈S,假設S中有k個元素,那麼這k個元素最多映射到k-1個元素,因此這個映射不可能時一一映射。如果存在這樣的i,我們僅需要把i從集合中移除即可。我們現在有一個含有n-1個元素且讓函數f映射到自身的集合A'=A-{i}。通過歸納假設我們知道如何去求解A'。如果不存在這樣的i,那麼映射就是一一映射,這樣我們就解決了問題。

這種解法的關鍵在於我們必須移除i。我們在上面證明了i不可能屬於S集。這是歸納法的優勢之處。一旦我們移除了一個元素縮減了問題的規模我們就算完成了。然而我們必須格外小心,縮減後的問題和原問題幾乎是一樣的。(除了規模外)對於集合A和函數f的唯一條件就是f讓A映射到自身。由於並沒有元素映射到i,這個條件對於A-{i}後的集合依然成立。當沒有元素可以移除的時候這個演算法也就執行結束了。

實現:上面的演算法是通過使用遞迴的過程加以描述的。在每一步中我們找到一個沒有其他元素映射到它的元素,移除它,然後繼續遞迴執行。然而實現方法並不需要用遞迴。我們可以對每一個元素i使用一個計數器c[i]。初始情況下c[i]需要和映射到i的元素數目相等。這可以通過掃描數組(進行n步)以及增加對應的計數器值而計算出來。然後我們把所有計數值為0的元素放在一個隊列中。在每一步執行中,我們移除隊列中的元素j(同時也移除集合中的對應值)。減小c[f(j)]的值,如果c[f(j)]=0,我們就把f(j)放在隊列中。當隊列為空白時演算法執行結束。演算法描述如下:

映射演算法(f:整型數組[1..n])
begin
  S:=A{A是從1到n的數字構成的數組}
  for j:=1 to n do c[j]:=0;
  for j:=1 to n do increament(c[f(j)]);
  for j:=1 to n do
    if c[j]=0 then put j in Queue;
  while Queue is not empty do
     remove i from the top of the queue;
     S:=S-{i};
  decrement c[f(i)];
  if c[f(i)]=0 then put f(i) in Queue
end;

 

 

複雜度:初始化部分需要O(n)的操作時間,每一個元素最多有一次機會被放置到隊列中,把元素從隊列中移除只需要常數時間。步驟的總數是O(n)。

總結:在本例中減少問題的規模主要在從集合中刪除元素上。因此我們試圖在不改變問題條件的情況下尋找一種最簡單的方法來移除元素。由於對於函數的唯一的要求是它必須把A映射到自身,故我們會很自然地選擇一個沒有其他元素映射到的元素。

檢查線段的包含情況【Q3】

問題:輸入是一條線上一系列間斷線段的集合I1,I2...In。對於每一個線段Ij都給出了它的兩個端點Lj(左端點),Rj(右端點)。我們想標記出所有包含在其他線段中的線段。換句話說,一個線段Ij必須被標記出來,如果存在另一條線段Ik(k≠j)並且滿足Lk≤Lj以及Rk≥Rj。為了簡化起見我們假定所有的線段都是不一樣的(例如任意兩個線段都不可能同時具有相同的左端點和右端點,但是它們可能有兩個端點中的某一個相同)。圖2展示了這樣的一個線段集合。(為了更好的展示,每一條線段都放在另一條線段上面而不是放在一條線上)

 


                                  圖2:線段集合

 

 

用直觀的方法使用歸納法主要是移除一個線段I,對於剩下的線段使用遞迴的方法加以解決,然後在檢查把I放回後的效果。問題在於把線段I放回需要檢查所有其他的線段來判斷他們中是否包含I或者被I所包含。這需要檢查I和其餘n-1條線段,演算法中使用的比較將達到n-1+n-2+...+1=n(n-1)/2次。為了獲得一個更好的演算法我們需要做兩件事:首先我們選擇一條特殊的線段加以移除,其次我們儘可能多的使用從更小規模問題的解決方案中收集到的資訊。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.