我试图找到一种优雅的方式来实现将数量分配到python中给定的一组槽中.
例如:
分布在4个平板上的7个橙子将返回:
[2, 2, 2, 1]
Run Code Online (Sandbox Code Playgroud)
4个板块上的10个橙子将是:
[3, 3, 2, 2]
Run Code Online (Sandbox Code Playgroud)
Mad*_*ist 40
从概念上讲,你想要做的是计算7 // 4 = 1和7 % 4 = 3.这意味着所有的盘子都变成了整个橙色.3的剩余部分告诉你三个板块得到额外的橙色.
该divmod内置是同时获得这两个量的快捷方式:
def distribute(oranges, plates):
base, extra = divmod(oranges, plates)
return [base + (i < extra) for i in range(plates)]
Run Code Online (Sandbox Code Playgroud)
用你的例子:
>>> distribute(oranges=7, plates=4)
[2, 2, 2, 1]
Run Code Online (Sandbox Code Playgroud)
为了完整起见,您可能希望检查oranges是否为非负数且plates为正数.鉴于这些条件,这里有一些额外的测试用例:
>>> distribute(oranges=7, plates=1)
[7]
>>> distribute(oranges=0, plates=4)
[0, 0, 0, 0]
>>> distribute(oranges=20, plates=2)
[10, 10]
>>> distribute(oranges=19, plates=4)
[5, 5, 5, 4]
>>> distribute(oranges=10, plates=4)
[3, 3, 2, 2]
Run Code Online (Sandbox Code Playgroud)
LSe*_*rni 15
你想看看Bresenham的绘制线算法(即在Y范围内分配X像素尽可能"直线";这对分布问题的应用是直截了当的).
这是我在这里找到的一个实现:
def get_line(start, end):
"""Bresenham's Line Algorithm
Produces a list of tuples from start and end
>>> points1 = get_line((0, 0), (3, 4))
>>> points2 = get_line((3, 4), (0, 0))
>>> assert(set(points1) == set(points2))
>>> print points1
[(0, 0), (1, 1), (1, 2), (2, 3), (3, 4)]
>>> print points2
[(3, 4), (2, 3), (1, 2), (1, 1), (0, 0)]
"""
# Setup initial conditions
x1, y1 = start
x2, y2 = end
dx = x2 - x1
dy = y2 - y1
# Determine how steep the line is
is_steep = abs(dy) > abs(dx)
# Rotate line
if is_steep:
x1, y1 = y1, x1
x2, y2 = y2, x2
# Swap start and end points if necessary and store swap state
swapped = False
if x1 > x2:
x1, x2 = x2, x1
y1, y2 = y2, y1
swapped = True
# Recalculate differentials
dx = x2 - x1
dy = y2 - y1
# Calculate error
error = int(dx / 2.0)
ystep = 1 if y1 < y2 else -1
# Iterate over bounding box generating points between start and end
y = y1
points = []
for x in range(x1, x2 + 1):
coord = (y, x) if is_steep else (x, y)
points.append(coord)
error -= abs(dy)
if error < 0:
y += ystep
error += dx
# Reverse the list if the coordinates were swapped
if swapped:
points.reverse()
return points
Run Code Online (Sandbox Code Playgroud)
疯狂物理学家的答案是完美的。但是,如果你要分发uniformley上板橘子(如2 3 2 3VS2 2 3 3在7个橙子和4个板为例),这里是一个简单的想法。
以 31 个橙子和 7 个盘子为例。
第 1 步:您像疯狂物理学家一样开始使用欧几里德除法:31 = 4*7 + 3。每个盘子里放 4 个橙子,剩下的 3 个。
[4, 4, 4, 4, 4, 4, 4]
Run Code Online (Sandbox Code Playgroud)
第 2 步:现在,您的盘子比橙子多,这完全不同:您必须在橙子之间分配盘子。您还剩 7 个盘子和 3 个橙子:7 = 2*3 + 1。每个橙子将有 2 个盘子(您还剩下一个盘子,但没关系)。让我们把这种2的leap。开始leap/2会很漂亮:
[4, 5, 4, 5, 4, 5, 4]
Run Code Online (Sandbox Code Playgroud)
那是最简单的情况。34 个橙子和 7 个盘子会发生什么?
第 1 步:您仍然像 Mad Physicist 一样开始使用欧几里得除法:34 = 4*7 + 6。每个盘子里放 4 个橙子,剩下的 6 个。
[4, 4, 4, 4, 4, 4, 4]
Run Code Online (Sandbox Code Playgroud)
第 2 步:现在,您还剩下 7 个盘子和 6 个橙子:7 = 1*6 + 1。每个橙子有一个盘子。但是等等……我没有 7 个橙子!别怕,我借给你一个苹果:
[5, 5, 5, 5, 5, 5, 4+apple]
Run Code Online (Sandbox Code Playgroud)
但是如果你想要一些统一,你必须把那个苹果放在别处!为什么不尝试在第一种情况下像橙子一样分发苹果?7个盘子,1个苹果:7 = 1*7 + 0。的leap是如图7所示,在开始leap/2,即3:
[5, 5, 5, 4+apple, 5, 5, 5]
Run Code Online (Sandbox Code Playgroud)
第 3 步。你欠我一个苹果。请把我的苹果还给我:
[5, 5, 5, 4, 5, 5, 5]
Run Code Online (Sandbox Code Playgroud)
总结一下:如果你只剩下几个橙子,你就分布峰,否则你分布谷。(免责声明:我是这个“算法”的作者,我希望它是正确的,但如果我错了,请纠正我!)
话不多说,上代码:
def distribute(oranges, plates):
base, extra = divmod(oranges, plates) # extra < plates
if extra == 0:
L = [base for _ in range(plates)]
elif extra <= plates//2:
leap = plates // extra
L = [base + (i%leap == leap//2) for i in range(plates)]
else: # plates/2 < extra < plates
leap = plates // (plates-extra) # plates - extra is the number of apples I lent you
L = [base + (1 - (i%leap == leap//2)) for i in range(plates)]
return L
Run Code Online (Sandbox Code Playgroud)
一些测试:
>>> distribute(oranges=28, plates=7)
[4, 4, 4, 4, 4, 4, 4]
>>> distribute(oranges=29, plates=7)
[4, 4, 4, 5, 4, 4, 4]
>>> distribute(oranges=30, plates=7)
[4, 5, 4, 4, 5, 4, 4]
>>> distribute(oranges=31, plates=7)
[4, 5, 4, 5, 4, 5, 4]
>>> distribute(oranges=32, plates=7)
[5, 4, 5, 4, 5, 4, 5]
>>> distribute(oranges=33, plates=7)
[5, 4, 5, 5, 4, 5, 5]
>>> distribute(oranges=34, plates=7)
[5, 5, 5, 4, 5, 5, 5]
>>> distribute(oranges=35, plates=7)
[5, 5, 5, 5, 5, 5, 5]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1255 次 |
| 最近记录: |