python编程导论_第十三课

学习安排(8月16日-8月20日)
1.主要学习视频Week6
链接(http://www.xuetangx.com/courses/MITx/6_00_2x/2014_T2/courseware/d39541ec36564a88af34d319a2f16bd7/
2.参考书第十二章--背包与图的最优化问题

解决问题时,如果涉及求最大、最小、最多、最少、最快、最低价格等情况,那么你就非常有可能将这个问题转换为一个典型的最优化问题,从而使用已知的计算方法进行解决。最优化问题通常包括两部分:

  • 目标函数:需要最大化或最小化的值。例如,波士顿和伊斯坦布尔之间的飞机票价。
  • 约束条件集合(可以为空):必须满足的条件集合。例如旅行时间的上界。

背包问题

假设窃贼有一个背包,最多能装20磅赃物,他闯入一户人家,发现图1中的物品。很显然,他不能把所有物品都装进背包,所以必须确定拿走哪些物品,留下哪些物品。他需要找出一组能够带走的价值最高的东西。


物品表

贪婪算法

对于这个问题,找出近似解的最简单方法就是贪婪算法。窃贼会首先选择最好的物品,然后是次好的,这样继续下去,直到将背包装满。当然,在此之前,窃贼必须确定什么是“最好”的。最好的物品是价值最高的,重量最轻的?还是具有最高价值/重量比值的呢?如果选择价值最高的物品,就应该只带电脑离开,这样可以得到200美元。如果选择重量最轻的,那么应该依次带走书、花瓶、收音机和油画,一共价值170美元。最后,如果确定“最好”的含义是价值/重量比值最高,那么应当首先拿走花瓶和钟。然后有三种物品的价值/重量比值都是10,但背包里只能放下书了。拿走书之后,他还可以拿走收音机。这样,所有赃物的价值是255美元。

对于这个数据集,尽管按照密度(价值与重量的比值)进行贪婪恰好得到了最优结果,但相对于按照重量或价值进行贪婪的算法来说,我们不能保证按照密度贪婪的算法一直能得到更好的解。更普遍地说,对于这种背包问题,无法确保使用贪婪算法找出的解是最优解。

0/1背包问题的最优解

假设我们认为近似解还不够好,那就需要找出这个问题的最优解。窃贼面临的问题恰好就是一种典型的最优化问题,称为0/1背包问题。 0/1背包问题可以定义如下。

  • 每个物品都可以用一个值对<价值, 重量>表示;
  • 背包能够容纳的物品总重量不能超过w;
  • 长度为n的向量I表示一个可用的物品集合,向量中的每个元素都代表一个物品;
  • 长度为n的向量V表示物品是否被窃贼带走。如果V[i] = 1,则物品I[i]被带走;如果V[i] = 0,
    则物品I[i]没有被带走;
  • 目标是找到一个V,使得:
    \sum_{i=0}^{n-1} V[i] * I[i].value
    的值最大,并满足约束条件:
    \sum_{i=0}^{n-1} V[i] * I[i].weight ≤ w
    我们看看如何简单直接地解决这个问题。
    (1) 枚举所有可能的物品组合。也就是说,生成物品集合的所有子集,即物品集合的幂集。
    (2) 去掉所有超过背包允许重量的物品组合。
    (3) 在余下的物品组合中,选出任意一个价值最大的组合。
    这种方法一定可以找到一个最优解。但如果初始物品集合很大,就需要运行很长时间。原因是随着物品数量的增长,子集数量呈现指数型增长。

图的最优化问题

一些典型图论问题

有很多著名的算法可以用来解决图的最优化问题,这是使用图论表示和解决问题的一个优势。以下是一些最著名的图的最优化问题。

  • 最短路径:对于两个节点n1和n2,找到边<s___n___, d___n___>(源节点和目标节点)的最短序列,使得:
    (1)第一条边的源节点是n1;
    (2)最后一条边的目标节点是n2;
    (3)对于序列中任意的边e1和e2,如果e2在序列中紧跟在e1后面,那么e2的源节点是e1的目标节点。
  • 最短加权路径:与最短路径非常相似,但它的目标不是找出连接两个节点的最短的边的序列。对于序列中边的权重,我们会定义某种函数(比如权重的和),并使这个函数的值最小化。 Google Maps计算两点之间的最短驾驶距离时,就是在解决这种问题。
  • 最大团: 团是一个节点集合,集合中每两个节点之间都有一条边。 最大团是一个图中规模最大的团。
  • 最小割:在一个图中,给定两个节点集合, 割就是一个边的集合。去掉这组边之后,一个节点集合中的每个节点和另一个节点集合中的每个节点之间都不存在任何相连的路径。最小割就是这样一个最小的边的集合。

最短路径:深度优先搜索和广度优先搜索

Facebook上具有“朋友”关系的两个人之间的距离。例如,你
会很想知道,你是否有这样一个朋友,他的朋友的朋友的朋友是米克·贾格尔。我们可以设计一个程序来回答这个问题。

朋友关系(至少在Facebook上)是对称的,例如,如果斯蒂芬妮是安德烈娅的朋友,那么安德烈娅也是斯蒂芬妮的朋友。因此,我们会使用Graph类型实现这个社交网络。然后可以定义寻找你和米克·贾格尔之间的最短连接的问题,如下所示。

  • 令G为表示朋友关系的无向图;
  • 对于G,找到一个最短的节点序列[你,……,米克·贾格尔],使得:如果n_in_{i+1}是路径中两个连续的节点,那么G中有一条边连接n_in_{i+1}
from graph import *

def printPath(path):
    """假设path是节点列表"""
    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函数实现的算法是递归形式的深度优先搜索算法。一般地,深度优先搜索算法开始时,会先选择起始节点的一个子节点,然后再选择这个子节点的一个子节点,以此类推,直到到达目标节点或者一个没有子节点的节点。然后,搜索开始回溯,返回到最近一个没有访问过的带有子节点的节点。遍历所有路径之后,算法就可以选择一个从起点到终点的最短路径(如果有)。

除了深度优先之外,还有其他方式对图进行遍历。另一种常用的方法称为广度优先搜索。广度优先搜索会先访问起始节点的所有子节点,如果这些子节点都不是最终节点,就继续访问每个子节点的所有子节点,以此类推。深度优先搜索经常使用递归实现,广度优先搜索则不同,它一般使用迭代来实现。 BFS会同时探索多条路径,每次迭代向每条路径添加一个节点。由于算法生成路径时是按照长度升序进行的,所以第一次找到的最终节点为目标节点的路径一定具有最少数量的边

在本例中,两种算法找出的是同样的路径。但如果图中两个节点之间的最短路径不止一条,那么DFS和BFS就不一定会找出同样的
最短路径。如上所述,如果要找出一条边数最少的路径,那么BFS更方便,因为它第一次找到的路径就一定是这样的路径。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 原文地址:http://theory.stanford.edu/~amitp/GameProgramming/ 1...
    达微阅读 19,386评论 0 28
  • 参见贪心算法——最短路径Dijkstra算法参见动态规划 目录 0.最短路径问题0.1 最短路径问题描述 0.1....
    王侦阅读 4,766评论 1 9
  • 目录 1.分支限界法简介1.1 分支限界法的本质——通过限界阻塞子树1.2 分支限界法与回溯法的区别1.3 下界或...
    王侦阅读 26,894评论 2 13
  • 奶奶上超市买了两个小碗,一个小碗上画有小动物的,还有一个小碗上画有小花儿的,奶奶说:梁澜你挑一个吧?我喜欢小动物的...
    李伟_bad4阅读 206评论 0 0
  • 我把钢笔放在了桌子的一旁。一位同学跑到我的桌旁时,一不小心,他碰撞到了我的桌子,我的钢笔掉到了地上。我赶快捡起,看...
    沈佳伟阅读 205评论 0 0