0

我有这个;

import operator
cuts = { "Emerald" : (10,125),
         "Oval" : (20,150),
         "Pear" : (35, 175),
         "Plumbbob" : (50,200),
         "Marquis" : (75, 230),
         "Crystal Ball" : (100, 260),
         "Brilliant" : (250, 350),
         "Star Cut" : (400,400),
         "Heart-shaped" : (1000, 500)
         }

def best(amount):
    "Returns most profitable cut's name."
    max_name = ""
    max_value = -10000
    for k,v in cuts.iteritems():
        value = ((float(amount) * (v[1] - 100) / 100)) - v[0]
        if value > max_value:
            max_value = value
            max_name = k
    return max_name

def create_table():
    """Creates a table like

       0-40 emerald
       40-45 Oval
       ...
       2000 + Heart-shaped
    """

但我坚持写作create_table。此代码用于帮助我正在玩的游戏。best函数,给定一个数量,返回该数量的最有利可图的切割名称。我想创建一个显示范围的表格。例如,对于 0-40 之间的数量,最佳切工是祖母绿,40-45 之间的最佳切工是椭圆形等。

4

2 回答 2

1
def create_table():
    curname = None
    for amount in xrange(2500):
        name = best(amount)
        if name != curname:
            if curname is not None:
                print "%d-%d %s" % (minamt, amount-1, curname)
            curname = name
            minamt = amount
    print "%d-%d %s" % (minamt, amount-1, curname)

(未测试,顺便说一句)

于 2012-06-25T00:43:05.933 回答
1

分析解决方案无疑是矫枉过正......但是,嘿,我喜欢矫枉过正。

首先,我转化cuts为 y=mx+b 格式:

cuts = [(k, (v1-100)*0.01,-v0) for k,(v0,v1) in cuts.items()]
cuts.sort()

导致

cuts = [
    ('Brilliant',       2.5,    -250),
    ('Crystal Ball',    1.6,    -100),
    ('Emerald',         0.25,    -10),
    ('Heart-shaped',    4.0,   -1000),
    ('Marquis',         1.3,     -75),
    ('Oval',            0.5,     -20),
    ('Pear',            0.75,    -35),
    ('Plumbbob',        1.0,     -50),
    ('Star Cut',        3.0,    -400)
]

对于每对切割,我可以找到交点 - 两个切割值相同的宝石尺寸

from itertools import combinations

xints = []
for (na,ma,ba),(nb,mb,bb) in combinations(cuts, 2):
    xint = (bb-ba)/(ma-mb)
    val = ma*xint + ba

    # figure out which cut dominates to the right
    va = ma*(xint+0.01)+ba
    vb = mb*(xint+0.01)+bb
    if vb > va:
        xints.append((xint,val,na,nb))
    else:
        xints.append((xint,val,nb,na))

这会产生 36 个交叉点,其中大部分是多余的 - 在这一点上,其他一些切割更有价值。所以我们过滤:

xints = [(xint,val,na,nb) for xint,val,na,nb in xints if all(nc==na or nc==nb or mc*xint+bc <= val for nc,mc,bc in cuts)]
xints.sort()

留下 10 个有效的交叉点:

[
    (40.0, 0.0, 'Emerald', 'Oval'),
    (60.0, 10.0, 'Oval', 'Pear'),
    (60.0, 10.0, 'Oval', 'Plumbbob'),
    (60.0, 10.0, 'Pear', 'Plumbbob'),
    (83.33333333333331, 33.333333333333314, 'Marquis', 'Crystal Ball'),
    (83.33333333333331, 33.333333333333314, 'Plumbbob', 'Crystal Ball'),
    (83.33333333333331, 33.333333333333314, 'Plumbbob', 'Marquis'),
    (166.66666666666669, 166.66666666666674, 'Crystal Ball', 'Brilliant'),
    (300.0, 500.0, 'Brilliant', 'Star Cut'),
    (600.0, 1400.0, 'Star Cut', 'Heart-shaped')
]

通过检查,我们看到 Pear 和 Marquis 切割是多余的——它们仅在交叉点处具有竞争力——因此我们丢弃它们出现的 4 个项目,得到

[
    (40.0, 0.0, 'Emerald', 'Oval'),
    (60.0, 10.0, 'Oval', 'Plumbbob'),
    (83.33333333333331, 33.333333333333314, 'Plumbbob', 'Crystal Ball'),
    (166.66666666666669, 166.66666666666674, 'Crystal Ball', 'Brilliant'),
    (300.0, 500.0, 'Brilliant', 'Star Cut'),
    (600.0, 1400.0, 'Star Cut', 'Heart-shaped')
]

哪些是最佳交叉点;然后你的桌子最终看起来像

Size      Value      Cut
----      -----     ------------
   0       -10
                    Emerald
  40         0
                    Oval
  60        10
                    Plumbbob
  83.33     33.33
                    Crystal Ball
 166.67    166.67
                    Brilliant
 300       500
                    Star Cut
 600      1400
                    Heart-shaped

严格来说,您可能会丢弃祖母绿切割,因为预期值是负数(对任何小于 40 的宝石进行切割都会让您损失金钱)。

于 2012-06-25T02:24:12.370 回答