博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2017阿里内推笔试题--算法工程师(运筹优化)
阅读量:4056 次
发布时间:2019-05-25

本文共 5778 字,大约阅读时间需要 19 分钟。

2017阿里内推笔试题–算法工程师(运筹优化)

题目

沐哲是一个菜鸟仓库的一个拣货员,但他有非常个怪异的习惯。每次拣货的重量都要比之前拣的一个轻,每次拣到货后都可以得到1块钱,沐哲想知道这样最多能赚多少钱

32 34 7 33 21 2
13 12 3 11 26 36
16 30 22 1 24 14
20 23 25 5 19 29
27 15 9 17 31 4
6 18 8 10 35 28
沐哲可以从仓库的某个货架开始拣货,下一步可以往上走,也可以往下走,当然,向左向右也可以,但必须使得下一个货物重量减小,才会去拣。在上面的仓库中,一条可拣货的路径为 25-22-3。当然30-23-20-16-13-12-3可以拣的货更多。这也是赚钱最多的一条路径。

要求

输入行数、列数和数据矩阵,输出所赚的最大钱数。

例子:
输入:
6 6
32 34 7 33 21 2
13 12 3 11 26 36
16 30 22 1 24 14
20 23 25 5 19 29
27 15 9 17 31 4
6 18 8 10 35 28
输出:
7

分析

此题应该属于树搜索的题目,拿到题目后一直在想怎么用动态规划。结果测试时间都过了,还是没做出来,真是搓的一笔。

最暴力的解法就是对每个点遍历,以每个点为起点进行深度优先搜索,找它相邻点的可行路径。搜索后将最大结果保存到当前位置,等遍历完后,找到矩阵元素的最大值,然后输出该值。

版本一

函数:

# check the (i,j) is in the matrix indexdef isInside(row,col,i,j):    return (i in range(row)) and (j in range(col))# get the max step from the current pointdef currentMaxStep(data,row,col,i,j):    max_step=0    directs = [(-1,0),(1,0),(0,-1),(0,1)]    for (dx,dy) in directs:        x,y = i+dx,j+dy        if(isInside(row,col,x,y) and data[x][y] < data[i][j]):            max_step = max([currentMaxStep(data,row,col,x,y),max_step])    return max_step + 1# traverse the whole data and generate the max step mapdef getMaxMap(data,row,col):    Map = [[0 for j in range(col)] for i in range(row)]    for i in range(row):        for j in range(col):            Map[i][j] = currentMaxStep(data,row,col,i,j)    print('the max step map is:')        for i in range(row):        print(Map[i])    return Map# find the max from the max step mapdef maxStep(data,row,col):    Map = getMaxMap(data,row,col)    return max([max(i) for i in Map])

测试结果:

if __name__=='__main__':    row,col = 6,6    data = [[32,  34,   7,  33,  21,   2],                [13,  12,   3,  11,  26,  36],                [16,  30,  22,  1,   24,  14],                [20,  23,  25,  5,   19,  29],                [27,  15,   9,  17,  31,   4],                [ 6,  18,   8,  10,  35,  28]]    print(maxStep(data,row,col))

输出:

the max step map is:[4, 5, 2, 3, 2, 1][3, 2, 1, 2, 5, 6][4, 7, 2, 1, 4, 1][5, 6, 7, 2, 3, 4][6, 3, 2, 3, 4, 1][1, 4, 1, 2, 5, 2]7

我们发现,每个点在进行深度优先搜索时,会遇到和其他点相同的路径,所以优化的空间。如果当前节点在之前已经搜索过了,这时候就需要判断需不需要继续搜索。两种情况

1、当前计算最大步数值大于之前遍历到该点的最大步数值,说明当前路径要比之前的路径更优,需要更新。
2、反之,不在搜索当前路径。
举个例子: 如data的第一个元素的最大路径为:32-13-12-3,最大步数为4; 当对第二个元素遍历时,假设按照上下左右的顺序,向下34-12-3为一条路径,此时第二元素的最大步数为3,向左34-32-13-12-3是个可行路径,而32-13-12-3之前已经搜索过,可以利用之前的32的最大步数值,直接比较4+1 和 3,更新第二元素的最大步数为5.
注意: 要实现这一操作,需要在遍历的过程中使用一个map来存储已遍历节点的最大步数值。

第二版

函数:

# check the (i,j) is in the matrix indexdef isInside(row,col,i,j):    return (i in range(row)) and (j in range(col))# update the local-max-step mapdef updateMap(data,Map,row,col,i,j):    directs = [(-1,0),(1,0),(0,-1),(0,1)]    for (dx,dy) in directs:        x,y = i+dx,j+dy        if(isInside(row,col,x,y) and data[x][y] > data[i][j] and Map[x][y] < Map[i][j]+1):            Map[x][y] = Map[i][j]+1            updateMap(data, Map,row,col,x,y)# find the max from the max step mapdef maxStep(data,row,col):    Map = [[1 for j in range(col)] for i in range(row)]    [updateMap(data,Map,row,col,i,j) for i in range(row) for j in range(col)]    print('the max step map is:')    [print(Map[i]) for i in range(row)]    return max([max(i) for i in Map])

测试结果:

if __name__=='__main__':    row,col = 6,6    data = [[32,  34,   7,  33,  21,   2],                [13,  12,   3,  11,  26,  36],                [16,  30,  22,  1,   24,  14],                [20,  23,  25,  5,   19,  29],                [27,  15,   9,  17,  31,   4],                [ 6,  18,   8,  10,  35,  28]]    print(maxStep(data,row,col))

输出:

the max step map is:[4, 5, 2, 3, 2, 1][3, 2, 1, 2, 5, 6][4, 7, 2, 1, 4, 1][5, 6, 7, 2, 3, 4][6, 3, 2, 3, 4, 1][1, 4, 1, 2, 5, 2]7

使用一个map记录已经遍历的元素的最大步长数可以避免一些重复的遍历。

还能不能优化呢?是否每个元素都有必要遍历一遍?
重最优化的角度来讲,此题实质上是解决从极大值到极小值的最长路径的问题。即最长路径一定是从极大值到极小值的一条路径(从山顶走到山底)。那么我们可以先找出所有最小值或者最大值,然后使用深度优先搜索遍历这些点,这些路径中,最大的一条路径一定是整个图中最大的路径。这就衍生了第三个版本(从极小值往上搜,是个上山的过程)。

版本三

函数:

# check the (i,j) is in the matrix indexdef isInside(row,col,i,j):    return (i in range(row)) and (j in range(col))# check data[i][j] is the local minimadef isLocalMinima(data,row,col,i,j):    directs = [(-1,0),(1,0),(0,-1),(0,1)]    invalid_directs = [isInside(row,col,i+dx,j+dy) and data[i][j]>data[i+dx][j+dy] for (dx,dy) in directs]    return not any(invalid_directs)# find the local minimadef findLocalMinimaElements(data,row,col):    minima = []    for i in range(row):        for j in range(col):            if isLocalMinima(data,row,col,i,j):                minima.append((i,j))    return minima# update the local-max-step mapdef updateMap(data,Map,row,col,i,j):    directs = [(-1,0),(1,0),(0,-1),(0,1)]    for (dx,dy) in directs:        x,y = i+dx,j+dy        if(isInside(row,col,x,y) and data[x][y] > data[i][j] and Map[x][y] < Map[i][j]+1):            Map[x][y] = Map[i][j]+1            updateMap(data, Map,row,col,x,y)   # main functiondef maxStep(data,row,col):    minima = findLocalMinimaElements(data,row,col)    Map = [[1 for j in range(col)] for i in range(row)]    for (min_x,min_y) in minima:        updateMap(data,Map,row,col,min_x,min_y)    print('the max step map is:')    [print(Map[i]) for i in range(row)]    return max([max(i) for i in Map])

测试结果:

if __name__=='__main__':    row,col = 6,6    data = [[32,  34,   7,  33,  21,   2],                [13,  12,   3,  11,  26,  36],                [16,  30,  22,  1,   24,  14],                [20,  23,  25,  5,   19,  29],                [27,  15,   9,  17,  31,   4],                [ 6,  18,   8,  10,  35,  28]]    print(maxStep(data,row,col))

输出:

the max step map is:[4, 5, 2, 3, 2, 1][3, 2, 1, 2, 5, 6][4, 7, 2, 1, 4, 1][5, 6, 7, 2, 3, 4][6, 3, 2, 3, 4, 1][1, 4, 1, 2, 5, 2]7

还能优化吗?

目前还没想到特别好的方法,只能以空间换时间。在对极小值进行深度优先搜索时,每个极小值可以独立使用一张图存储可行路径上每个元素的最大步数值。然后使用多线程跑,最优比较这些图中的最大值,即为最大步数。这个对大数据矩阵应该会有效果吧。

完整的测试代码放到github上了,有需要的可以下载:

转载地址:http://prhci.baihongyu.com/

你可能感兴趣的文章
Centos 7(Linux)环境下安装PHP(编译添加)相应动态扩展模块so(以openssl.so为例)
查看>>
fastcgi_param 详解
查看>>
Nginx配置文件(nginx.conf)配置详解
查看>>
标记一下
查看>>
IP报文格式学习笔记
查看>>
autohotkey快捷键显示隐藏文件和文件扩展名
查看>>
Linux中的进程
查看>>
学习python(1)——环境与常识
查看>>
学习设计模式(3)——单例模式和类的成员函数中的静态变量的作用域
查看>>
自然计算时间复杂度杂谈
查看>>
当前主要目标和工作
查看>>
使用 Springboot 对 Kettle 进行调度开发
查看>>
一文看清HBase的使用场景
查看>>
解析zookeeper的工作流程
查看>>
搞定Java面试中的数据结构问题
查看>>
慢慢欣赏linux make uImage流程
查看>>
linux内核学习(7)脱胎换骨解压缩的内核
查看>>
以太网基础知识
查看>>
慢慢欣赏linux 内核模块引用
查看>>
kprobe学习
查看>>