需要帮助设计解决方案来计算"惩罚"自动换行功能

时间:2014-06-04 06:13:23

标签: python algorithm recursion

我有一个程序,递归地将自动换行计算到指定的行长度。

def wrap(input, lineSpaces):
    if len(input) <= lineSpaces: # Base case
        return input
    temp = input.rfind(" ", 0, lineSpaces - 1) # Parsing
    if temp == -1:
        return input
    else:
        prev = input[:temp+1]
        next = wrap(input[temp+1:], lineSpaces)
        wrap.penalty = (lineSpaces-len(prev)+1)**3 +(lineSpaces-len(next)+1)**3 # Penalty calculation
        return prev+'\n'+next


# I/O
list = []
penalties = []
M = int(raw_input())
for i in xrange(0, M):
    lineSpaces = int(raw_input())
    input = raw_input()
    list.append(wrap(input, lineSpaces))
    penalties.append(wrap.penalty)


for i in xrange(0, len(list)):
    print "penalty: ", penalties[i]
    print list[i]+"\n"

使用以下输入:

3
20
This is the first paragraph that you need to print
30
This is another paragraph that you need to print and it ends in a very long word onetwothreefourfivesixseven
36
This paragraph all fits on one line

我期待输出:

penalty: 35
This is the first
paragraph that you
need to print

penalty: 216
This is another paragraph
that you need to print and 
it ends in a very long word
onetwothreefourfivesixseven

penalty: 0
This paragraph all fits on one line

然而,我实际上得到了输出:

penalty:  -1701
This is the first 
paragraph that you 
need to print

penalty:  -148752
This is another paragraph 
that you need to print and 
it ends in a very long word 
onetwothreefourfivesixseven

penalty:  -148752
This paragraph all fits on one line

你可以看到,我的惩罚输出是错误的。我想将我的罚分计算为每个段落中所有行的(lineSpaces-len(line)+1)**3之和,除了每个段落的最后一行,罚分为0.似乎每次调用(lineSpaces-len(prev)+1)**3段落(除了最后一个,应该是0)返回正确的值。我的逻辑有什么问题?

1 个答案:

答案 0 :(得分:1)

您在某些方面对罚款的计算是错误的。首先,将next设置为等于递归调用的返回值。这仍然与原始版本一样长,或者更长,因为您所做的就是为它添加换行符。但是你计算了这个惩罚。在每次调用时,您正在计算该调用适合一行的惩罚,以及传递给下一个递归调用的其他所有内容的惩罚。

此外,因为您将此值存储在wrap.penalty上,所以在每次调用后都会覆盖它。由于您从未对wrap.penalty的旧值执行任何操作,因此忽略除最后一个之外的所有计算。

使用函数属性来存储这样的数据是一个危险的游戏。只有一个 wrap,因此只有一个wrap.penalty,所以它不像每个递归调用都有自己的版本penalty;他们都在踩着同一个人。而不是将值存储在wrap.penalty中,最好将它与包装文本一起返回,如下所示:

def wrap(instr, lineSpaces):
    if len(instr) <= lineSpaces: # Base case
        return instr, 0
    temp = instr.rfind(" ", 0, lineSpaces - 1) # Parsing
    if temp == -1:
        return instr, 0
    else:
        prev = instr[:temp+1]
        next, penalty = wrap(instr[temp+1:], lineSpaces)
        penalty += (lineSpaces-len(prev)+1)**3 # Penalty calculation
        return prev+'\n'+next, penalty

然后:

>>> wrap("This is the first paragraph that you need to print", 20)
('This is the first \nparagraph that you \nneed to print', 35)

在每次调用时,我将从递归调用返回的惩罚添加到为刚刚解析的行计算的惩罚。 Pham Trung在评论中建议,你也可以在包装后的单独步骤中计算惩罚。

我还将您的变量名称从input更改为instr。您应该避免使用名称input,因为该名称有内置函数。 (出于同样的原因,list也不是变量的好名称。)