python編程導(dǎo)論_第十三課

學(xué)習(xí)安排(8月16日-8月20日)
1.主要學(xué)習(xí)視頻Week6
鏈接(http://www.xuetangx.com/courses/MITx/6_00_2x/2014_T2/courseware/d39541ec36564a88af34d319a2f16bd7/
2.參考書第十二章--背包與圖的最優(yōu)化問題

解決問題時(shí),如果涉及求最大怔蚌、最小、最多幅聘、最少窖贤、最快怎囚、最低價(jià)格等情況捉撮,那么你就非常有可能將這個(gè)問題轉(zhuǎn)換為一個(gè)典型的最優(yōu)化問題灾梦,從而使用已知的計(jì)算方法進(jìn)行解決。最優(yōu)化問題通常包括兩部分:

  • 目標(biāo)函數(shù):需要最大化或最小化的值槐雾。例如夭委,波士頓和伊斯坦布爾之間的飛機(jī)票價(jià)。
  • 約束條件集合(可以為空):必須滿足的條件集合募强。例如旅行時(shí)間的上界株灸。

背包問題

假設(shè)竊賊有一個(gè)背包,最多能裝20磅贓物钻注,他闖入一戶人家蚂且,發(fā)現(xiàn)圖1中的物品。很顯然幅恋,他不能把所有物品都裝進(jìn)背包,所以必須確定拿走哪些物品泵肄,留下哪些物品捆交。他需要找出一組能夠帶走的價(jià)值最高的東西淑翼。


物品表

貪婪算法

對(duì)于這個(gè)問題,找出近似解的最簡(jiǎn)單方法就是貪婪算法品追。竊賊會(huì)首先選擇最好的物品玄括,然后是次好的,這樣繼續(xù)下去肉瓦,直到將背包裝滿遭京。當(dāng)然,在此之前泞莉,竊賊必須確定什么是“最好”的哪雕。最好的物品是價(jià)值最高的,重量最輕的鲫趁?還是具有最高價(jià)值/重量比值的呢斯嚎?如果選擇價(jià)值最高的物品,就應(yīng)該只帶電腦離開挨厚,這樣可以得到200美元堡僻。如果選擇重量最輕的,那么應(yīng)該依次帶走書疫剃、花瓶钉疫、收音機(jī)和油畫,一共價(jià)值170美元巢价。最后陌选,如果確定“最好”的含義是價(jià)值/重量比值最高,那么應(yīng)當(dāng)首先拿走花瓶和鐘蹄溉。然后有三種物品的價(jià)值/重量比值都是10咨油,但背包里只能放下書了。拿走書之后柒爵,他還可以拿走收音機(jī)役电。這樣,所有贓物的價(jià)值是255美元棉胀。

對(duì)于這個(gè)數(shù)據(jù)集法瑟,盡管按照密度(價(jià)值與重量的比值)進(jìn)行貪婪恰好得到了最優(yōu)結(jié)果,但相對(duì)于按照重量或價(jià)值進(jìn)行貪婪的算法來說唁奢,我們不能保證按照密度貪婪的算法一直能得到更好的解霎挟。更普遍地說,對(duì)于這種背包問題麻掸,無法確保使用貪婪算法找出的解是最優(yōu)解酥夭。

0/1背包問題的最優(yōu)解

假設(shè)我們認(rèn)為近似解還不夠好,那就需要找出這個(gè)問題的最優(yōu)解。竊賊面臨的問題恰好就是一種典型的最優(yōu)化問題熬北,稱為0/1背包問題疙描。 0/1背包問題可以定義如下。

  • 每個(gè)物品都可以用一個(gè)值對(duì)<價(jià)值, 重量>表示讶隐;
  • 背包能夠容納的物品總重量不能超過w起胰;
  • 長(zhǎng)度為n的向量I表示一個(gè)可用的物品集合,向量中的每個(gè)元素都代表一個(gè)物品巫延;
  • 長(zhǎng)度為n的向量V表示物品是否被竊賊帶走效五。如果V[i] = 1,則物品I[i]被帶走炉峰;如果V[i] = 0畏妖,
    則物品I[i]沒有被帶走;
  • 目標(biāo)是找到一個(gè)V讲冠,使得:
    \sum_{i=0}^{n-1} V[i] * I[i].value
    的值最大瓜客,并滿足約束條件:
    \sum_{i=0}^{n-1} V[i] * I[i].weight ≤ w
    我們看看如何簡(jiǎn)單直接地解決這個(gè)問題。
    (1) 枚舉所有可能的物品組合竿开。也就是說谱仪,生成物品集合的所有子集,即物品集合的冪集否彩。
    (2) 去掉所有超過背包允許重量的物品組合疯攒。
    (3) 在余下的物品組合中,選出任意一個(gè)價(jià)值最大的組合列荔。
    這種方法一定可以找到一個(gè)最優(yōu)解敬尺。但如果初始物品集合很大,就需要運(yùn)行很長(zhǎng)時(shí)間贴浙。原因是隨著物品數(shù)量的增長(zhǎng)砂吞,子集數(shù)量呈現(xiàn)指數(shù)型增長(zhǎng)。

圖的最優(yōu)化問題

一些典型圖論問題

有很多著名的算法可以用來解決圖的最優(yōu)化問題崎溃,這是使用圖論表示和解決問題的一個(gè)優(yōu)勢(shì)蜻直。以下是一些最著名的圖的最優(yōu)化問題。

  • 最短路徑:對(duì)于兩個(gè)節(jié)點(diǎn)n1和n2袁串,找到邊<s___n___, d___n___>(源節(jié)點(diǎn)和目標(biāo)節(jié)點(diǎn))的最短序列概而,使得:
    (1)第一條邊的源節(jié)點(diǎn)是n1;
    (2)最后一條邊的目標(biāo)節(jié)點(diǎn)是n2囱修;
    (3)對(duì)于序列中任意的邊e1和e2赎瑰,如果e2在序列中緊跟在e1后面,那么e2的源節(jié)點(diǎn)是e1的目標(biāo)節(jié)點(diǎn)破镰。
  • 最短加權(quán)路徑:與最短路徑非常相似餐曼,但它的目標(biāo)不是找出連接兩個(gè)節(jié)點(diǎn)的最短的邊的序列压储。對(duì)于序列中邊的權(quán)重,我們會(huì)定義某種函數(shù)(比如權(quán)重的和)晋辆,并使這個(gè)函數(shù)的值最小化渠脉。 Google Maps計(jì)算兩點(diǎn)之間的最短駕駛距離時(shí)宇整,就是在解決這種問題瓶佳。
  • 最大團(tuán): 團(tuán)是一個(gè)節(jié)點(diǎn)集合,集合中每?jī)蓚€(gè)節(jié)點(diǎn)之間都有一條邊鳞青。 最大團(tuán)是一個(gè)圖中規(guī)模最大的團(tuán)霸饲。
  • 最小割:在一個(gè)圖中,給定兩個(gè)節(jié)點(diǎn)集合臂拓, 割就是一個(gè)邊的集合厚脉。去掉這組邊之后,一個(gè)節(jié)點(diǎn)集合中的每個(gè)節(jié)點(diǎn)和另一個(gè)節(jié)點(diǎn)集合中的每個(gè)節(jié)點(diǎn)之間都不存在任何相連的路徑胶惰。最小割就是這樣一個(gè)最小的邊的集合傻工。

最短路徑:深度優(yōu)先搜索和廣度優(yōu)先搜索

Facebook上具有“朋友”關(guān)系的兩個(gè)人之間的距離。例如孵滞,你
會(huì)很想知道中捆,你是否有這樣一個(gè)朋友,他的朋友的朋友的朋友是米克·賈格爾坊饶。我們可以設(shè)計(jì)一個(gè)程序來回答這個(gè)問題泄伪。

朋友關(guān)系(至少在Facebook上)是對(duì)稱的,例如匿级,如果斯蒂芬妮是安德烈婭的朋友蟋滴,那么安德烈婭也是斯蒂芬妮的朋友。因此痘绎,我們會(huì)使用Graph類型實(shí)現(xiàn)這個(gè)社交網(wǎng)絡(luò)津函。然后可以定義尋找你和米克·賈格爾之間的最短連接的問題,如下所示孤页。

  • 令G為表示朋友關(guān)系的無向圖尔苦;
  • 對(duì)于G,找到一個(gè)最短的節(jié)點(diǎn)序列[你散庶,……蕉堰,米克·賈格爾],使得:如果n_in_{i+1}是路徑中兩個(gè)連續(xù)的節(jié)點(diǎn)悲龟,那么G中有一條邊連接n_in_{i+1}屋讶。
from graph import *

def printPath(path):
    """假設(shè)path是節(jié)點(diǎn)列表"""
    result = ''
    for i in range(len(path)):
        result = result + str(path[i])
        if i != len(path) - 1:
            result = result + '->'
    return result

def DFS(graph, start, end, path = [], shortest = None):
    #assumes graph is a Digraph
    #assumes start and end are nodes in graph
    path = path + [start]
    print 'Current dfs path:', printPath(path)
    if start == end:
        return path
    for node in graph.childrenOf(start):
        if node not in path: #avoid cycles
            newPath = DFS(graph,node,end,path,shortest)
            if newPath != None:
                return newPath

def DFSShortest(graph, start, end, path = [], shortest = None):
    #assumes graph is a Digraph
    #assumes start and end are nodes in graph
    path = path + [start]
    print 'Current dfs path:', printPath(path)
    if start == end:
        return path
    for node in graph.childrenOf(start):
        if node not in path: #avoid cycles
            if shortest == None or len(path)<len(shortest):
                newPath = DFSShortest(graph,node,end,path,shortest)
                if newPath != None:
                    shortest = newPath
    return shortest


def testSP():
    nodes = []
    for name in range(6):
        nodes.append(Node(str(name)))
    g = Digraph()
    for n in nodes:
        g.addNode(n)
    g.addEdge(Edge(nodes[0],nodes[1]))
    g.addEdge(Edge(nodes[1],nodes[2]))
    g.addEdge(Edge(nodes[2],nodes[3]))
    g.addEdge(Edge(nodes[2],nodes[4]))
    g.addEdge(Edge(nodes[3],nodes[4]))
    g.addEdge(Edge(nodes[3],nodes[5]))
    g.addEdge(Edge(nodes[0],nodes[2]))
    g.addEdge(Edge(nodes[1],nodes[0]))
    g.addEdge(Edge(nodes[3],nodes[1]))
    g.addEdge(Edge(nodes[4],nodes[0]))
    sp = DFS(g, nodes[0], nodes[5])
    print 'Shortest path found by DFS:', printPath(sp)


def BFS(graph, start, end, q = []):
    initPath = [start]
    q.append(initPath)
    while len(q) != 0:
        tmpPath = q.pop(0)
        lastNode = tmpPath[len(tmpPath) - 1]
        print 'Current dequeued path:', printPath(tmpPath)
        if lastNode == end:
            return tmpPath
        for linkNode in graph.childrenOf(lastNode):
            if linkNode not in tmpPath:
                newPath = tmpPath + [linkNode]
                q.append(newPath)
    return None

DFS函數(shù)實(shí)現(xiàn)的算法是遞歸形式的深度優(yōu)先搜索算法。一般地须教,深度優(yōu)先搜索算法開始時(shí)皿渗,會(huì)先選擇起始節(jié)點(diǎn)的一個(gè)子節(jié)點(diǎn)斩芭,然后再選擇這個(gè)子節(jié)點(diǎn)的一個(gè)子節(jié)點(diǎn),以此類推乐疆,直到到達(dá)目標(biāo)節(jié)點(diǎn)或者一個(gè)沒有子節(jié)點(diǎn)的節(jié)點(diǎn)划乖。然后,搜索開始回溯挤土,返回到最近一個(gè)沒有訪問過的帶有子節(jié)點(diǎn)的節(jié)點(diǎn)琴庵。遍歷所有路徑之后,算法就可以選擇一個(gè)從起點(diǎn)到終點(diǎn)的最短路徑(如果有)仰美。

除了深度優(yōu)先之外迷殿,還有其他方式對(duì)圖進(jìn)行遍歷。另一種常用的方法稱為廣度優(yōu)先搜索咖杂。廣度優(yōu)先搜索會(huì)先訪問起始節(jié)點(diǎn)的所有子節(jié)點(diǎn)庆寺,如果這些子節(jié)點(diǎn)都不是最終節(jié)點(diǎn),就繼續(xù)訪問每個(gè)子節(jié)點(diǎn)的所有子節(jié)點(diǎn)诉字,以此類推懦尝。深度優(yōu)先搜索經(jīng)常使用遞歸實(shí)現(xiàn),廣度優(yōu)先搜索則不同壤圃,它一般使用迭代來實(shí)現(xiàn)陵霉。 BFS會(huì)同時(shí)探索多條路徑,每次迭代向每條路徑添加一個(gè)節(jié)點(diǎn)埃唯。由于算法生成路徑時(shí)是按照長(zhǎng)度升序進(jìn)行的撩匕,所以第一次找到的最終節(jié)點(diǎn)為目標(biāo)節(jié)點(diǎn)的路徑一定具有最少數(shù)量的邊

在本例中,兩種算法找出的是同樣的路徑墨叛。但如果圖中兩個(gè)節(jié)點(diǎn)之間的最短路徑不止一條止毕,那么DFS和BFS就不一定會(huì)找出同樣的
最短路徑。如上所述漠趁,如果要找出一條邊數(shù)最少的路徑扁凛,那么BFS更方便,因?yàn)樗谝淮握业降穆窂骄鸵欢ㄊ沁@樣的路徑闯传。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谨朝,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子甥绿,更是在濱河造成了極大的恐慌字币,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件共缕,死亡現(xiàn)場(chǎng)離奇詭異洗出,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)图谷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門翩活,熙熙樓的掌柜王于貴愁眉苦臉地迎上來阱洪,“玉大人,你說我怎么就攤上這事菠镇∪咻” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵利耍,是天一觀的道長(zhǎng)蚌本。 經(jīng)常有香客問我,道長(zhǎng)堂竟,這世上最難降的妖魔是什么魂毁? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任玻佩,我火速辦了婚禮出嘹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘咬崔。我一直安慰自己税稼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布垮斯。 她就那樣靜靜地躺著郎仆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪兜蠕。 梳的紋絲不亂的頭發(fā)上扰肌,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音熊杨,去河邊找鬼曙旭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛晶府,可吹牛的內(nèi)容都是我干的桂躏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼川陆,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼剂习!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起较沪,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤鳞绕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后尸曼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體们何,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年骡苞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了垂蜗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片楷扬。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖贴见,靈堂內(nèi)的尸體忽然破棺而出烘苹,到底是詐尸還是另有隱情,我是刑警寧澤片部,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布镣衡,位于F島的核電站,受9級(jí)特大地震影響档悠,放射性物質(zhì)發(fā)生泄漏廊鸥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一辖所、第九天 我趴在偏房一處隱蔽的房頂上張望惰说。 院中可真熱鬧,春花似錦缘回、人聲如沸吆视。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽啦吧。三九已至,卻和暖如春拙寡,著一層夾襖步出監(jiān)牢的瞬間授滓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工肆糕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留般堆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓擎宝,卻偏偏與公主長(zhǎng)得像郁妈,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子绍申,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

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

  • 原文地址:http://theory.stanford.edu/~amitp/GameProgramming/ 1...
    達(dá)微閱讀 19,446評(píng)論 0 28
  • 參見貪心算法——最短路徑Dijkstra算法參見動(dòng)態(tài)規(guī)劃 目錄 0.最短路徑問題0.1 最短路徑問題描述?0.1....
    王偵閱讀 4,812評(píng)論 1 9
  • 目錄 1.分支限界法簡(jiǎn)介1.1 分支限界法的本質(zhì)——通過限界阻塞子樹1.2 分支限界法與回溯法的區(qū)別1.3 下界或...
    王偵閱讀 27,192評(píng)論 2 13
  • 奶奶上超市買了兩個(gè)小碗噩咪,一個(gè)小碗上畫有小動(dòng)物的,還有一個(gè)小碗上畫有小花兒的极阅,奶奶說:梁瀾你挑一個(gè)吧胃碾?我喜歡小動(dòng)物的...
    李偉_bad4閱讀 209評(píng)論 0 0
  • 我把鋼筆放在了桌子的一旁。一位同學(xué)跑到我的桌旁時(shí)筋搏,一不小心仆百,他碰撞到了我的桌子,我的鋼筆掉到了地上奔脐。我趕快撿起俄周,看...
    沈佳偉閱讀 210評(píng)論 0 0