1. 程式人生 > >python數據結構與算法之問題求解實例

python數據結構與算法之問題求解實例

算法設計 一個表 程序 nbsp ice 元素 因此 需要 測試

關於問題求解,書中有一個實際的案例。

技術分享圖片

上圖是一個交叉路口的模型,現在問題是,怎麽安排紅綠燈才可以保證相應的行駛路線互不交錯。

第一步,就是把問題弄清楚。

怎麽能讓每一條行駛路線不沖突呢?

其實,就是給所有的行駛路線分組(這樣保證了安全問題,不會撞車)。

並且,所做的分組應該盡可能大一些,用以提高路口的通行效率(經濟問題,如果一個組一條路線,雖然不會撞車,但是等待的時間會很長)。

有了上面的最大化分組的想法。那麽就進一步將問題具體化。

這個路口有13個可供行駛的方向:AB,AC,AD,BA,BC,BD,DA,DB,DC,EA,EB,EC,ED。

現在問題就轉化為,給這13條路線分組,使其各個組不沖突,並且最大化組中的成員。

在書中引出了一個沖突圖,用來表示各個路線的沖突。

技術分享圖片

其中圖中元素稱之為頂點,連線稱之為邊或者弧。相互之間有邊的頂點稱為鄰接頂點。

安全分組就變成了另外一種說法,為沖突圖中的頂點確定一種分組,保證屬於同一分組的所有頂點互不鄰接。

到了這裏就完了第一步,將問題嚴格化。

第二步,就是進行數據結構與算法設計

使用什麽樣的數據結構來表示沖突中的形式路線,又用哪種算法來計算分組。

書中首先提到了一個最佳著色算法,其實就是著名的四色問題,這個算法能找到最佳的分組方案。但是由於算法代價太高,效率不高。因此著重介紹了一個更為簡單的算法。

那就是貪心法。它的基本想法是這樣的:利用當時掌握的信息,盡可能地向得到解的方向前進,知道不能繼續再換一個方法。

那麽在這個例子中的具體表現就是:就是確定一個分組,這個分組裏的成員互相都不鄰接,也就是說不能沖突。當這個分組完成之後,再確定下一個分組。

按照這個方法,上面的例子分組就是:

{AB,AC,AD,BA,DC,ED}

{BC,BD,EA}

{DA,DB}

{EB,EC}

算法的偽代碼如下:

輸入:圖G #記錄著圖中頂點連接的關系

集合verts保存G中所有的頂點 #建立初始狀態

設置集合groups為空集 #記錄得到的分組,元素是頂點集合

while 存在未著色頂點:

  選一種新的顏色

  在未著色頂點中給盡量多的無連邊的點著色(構建一個分組)

  記錄新著色的頂點組

python偽代碼:

new_group = 空集

for v in verts:

  if v 與new_group集合中的頂點都不相連:

    將v從verts中取出

    new_group.add(v)

循環結束時,new_grouo是可以用一種新的顏色著色的頂點集合

第三步,編寫代碼。

其實,上面的偽代碼已經接近於具體程序了。只是還有一些細節需要考慮。

1、如何表示顏色。這個簡單,用整數就可以。其實,用不用顏色表示都可以,只要將每個分組分開即可。這裏采用二元組來表示,一個表示顏色,一個表示分好的組。、

2、如何記錄分組。可以用一個集合來記錄,也就是groups是集合的集合。

3、如何表示圖結構?這個比較難,是後面的內容,這裏先略過。

由此可得出python的代碼:

def coloring(G)

  color = 0

  groups = set()

  verts = vertices(G) #用來獲取所有的頂點

  while verts:

    new_groups = set()

    for v in list(verts):

      if not_adjacent_with_set(v, newgroup, G):

        new_group.add(v)

        verts.remove(v)

    groups.add((color, new_group))

    color += 1

  return grous

第四步,測試代碼,尋找一些邊界例子測試代碼的嚴謹性以及邏輯性。

由於,這裏並不是一個完整的項目,而且這個例子比較簡單,就簡單分析討論一下,應該註意的幾個問題。

1、它的解唯一嗎?

其實,大致觀察一下,就會發現,上面的算法只能給出一個恰好的解。例如,下面的分組也是一個解

{AB,EB,EC}

{AC,AD,BC,}

{BA,BD,DB,ED}

{DA,DC,EA}

其實,經過分析。對於BA、DC、ED三個頂點,將它們放在任何一個分組都是可以的。因為它們不跟任何一個頂點相連,也就是公認的無害右轉彎。對於這個設計具體得看對於沖突概念的定義。

2、再次回顧一下算法的實現跟原來的問題是否相符

原來的問題是怎麽分配,各個路線才能不沖突。

而上面的算法給出了一種不沖突的方法,但並不是最優的解。比如:上面的算法中每個分組都頂點都不允許重復,也就是各個分組互不相交。但真正的問題並沒有這個要求。無害的右轉彎就與各個分組都不沖突,完全可以都分配在各個分組裏面。使其得到下面的分配:

{AB,AC,AD,BA,DC,ED}

{BC,BD,EA,BA,DC,ED}

{DA,DB,BA,DC,ED}

{EB,EC,BA,DC,ED}

這樣就會將分組盡可能地擴充,使其經濟效率更高(這個分組還可以繼續擴充為{DA,DB,BA,DC,ED,AD})。

當然,這個問題還會有其他的一些具體的問題,這裏就不討論了。作者主要是用一個例子來帶我們分析了一下,如何將生活中的實際問題,一步一步通過分析設計,最終得到一個完整的正確的效率高的計算機程序。

  

python數據結構與算法之問題求解實例