Text Justification / Word Wrap dp problem.Unable 在我的递归中找到重叠条件?
Text Justification / Word Wrap dp problem.Unable to find the overlapping condition in my recursion?
阙:https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap
我尝试过的和遇到的问题:我尝试了一种递归方法来解决这个问题。目前,无法找到重叠的子问题。谁能帮助我如何优化、记忆和 modify/update 我的递归方法?。 (我认为我的方法是错误的)
方法: 单词在当前行中(当且仅当 space 被留下时)或者将在新行中。
代码流:
Input text = "Cat is on Floor" .
I stored len in an array = [3,2,2,5]
ans(a,b,c) : a: index, b: line (currently no use), c: current line sum
base condn if all elements are over a>=size: return pow(spaceleft,2)
will return min( subproblem(word in current line),subproblem(word in new line)+pow(spaceleft,2))
Initially : ans(1,1,3)
ans(2,1,6) ans(2,2,2)
ans(3,2,2) ans(3,2,5) ans(3,3,2)
ans(4,3,5) ans(4,3,5) ans(4,4,5)
下面的代码在python3.x:
n=6
arr=[3,2,2,5]
size = 4
def ans(a,b,c):
if(a>=size):
return pow((n-c),2);
if(c+arr[a]+1 > n):
return (pow((n-c),2)+ans(a+1,b+1,arr[a]))
return (min(ans(a+1,b,c+arr[a]+1),pow((n-c),2)+ans(a+1,b+1,arr[a])))
print(ans(1,1,3))
在此先感谢您抽出宝贵的时间帮助我....
我认为您的表述可能遗漏了一些案例。这肯定很难理解。这是一个似乎得到正确答案的答案。
class LineWrapper:
def __init__(self, lens, width):
self.lens = lens
self.width = width;
def cost(self, ptr=0, used=0):
remaining = self.width - used
# Case 1: No words: Cost is due to partially used line.
if ptr == len(self.lens):
return remaining ** 2 if used else 0
# Case 2: First word of line. Must skip.
if used == 0:
return self.cost(ptr + 1, self.lens[ptr])
# Case 3: Out of space. Must wrap.
needed = 1 + self.lens[ptr]
if remaining < needed:
return remaining ** 2 + self.cost(ptr)
# Case 4: Min cost of skip and wrap.
return min(self.cost(ptr + 1, used + needed), remaining ** 2 + self.cost(ptr))
这个公式中的子问题有很多重叠,你的也是。一个简单的示例是宽度为 7 的 [1, 1, 1, 1]。解决方案将尝试将其放在 1、2、3 和 4 行的所有组合上。可能子组合会重复。
为了更清楚地看到这一点,我们可以记忆并检查命中:
def memo_cost(self, ptr=0, used=0):
args = (ptr, used)
print(args)
if args in self.memos:
print(f'Memo hit: {args}')
return self.memos[args]
remaining = self.width - used
# Case 1: No words has cost of partially used line
if ptr == len(self.lens):
r = remaining ** 2 if used else 0
self.memos[args] = r
print(f'Done: {r}')
return r
# Case 2: First word of line. Must skip.
if used == 0:
r = self.memo_cost(ptr + 1, self.lens[ptr])
self.memos[args] = r
print(f'Must skip: {r}')
return r
# Case 3: Out of space. Must wrap.
needed = 1 + self.lens[ptr]
if remaining < needed:
r = remaining ** 2 + self.memo_cost(ptr)
self.memos[args] = r
print(f'Must wrap: {r}')
return r
# Case 4: Min cost of skip wrap and wrap.
r = min(remaining ** 2 + self.memo_cost(ptr), self.memo_cost(ptr + 1, used + needed))
self.memos[args] = r
print(f'Min: {r}')
return r
print(LineWrapper([1, 1, 1, 1], 7).memo_cost())
当 运行 时,会产生:
$ python3 lb.py
(0, 0)
(1, 1)
(1, 0)
(2, 1)
(2, 0)
(3, 1)
(3, 0)
(4, 1)
Done: 36
Must skip: 36
(4, 3)
Done: 16
Min: 16
Must skip: 16
(3, 3)
(3, 0)
Memo hit: (3, 0)
(4, 5)
Done: 4
Min: 4
Min: 4
Must skip: 4
(2, 3)
(2, 0)
Memo hit: (2, 0)
(3, 5)
(3, 0)
Memo hit: (3, 0)
(4, 7)
Done: 0
Min: 0
Min: 0
Min: 0
Must skip: 0
0
感谢@Gene,我的回答带有备忘录
n=7
arr=[3,2,2,5]
INF = 9223372036854775807
size = 4
dp = [[INF for i in range(n+1)] for j in range(size+1)]
def ans(a,b,c):
if(dp[a][c]!=INF):
return dp[a][c]
if(a>=size):
dp[a][c] = pow((n-c),2)
return pow((n-c),2)
if(c+arr[a]+1 > n):
dp[a][c] = (pow((n-c),2)+ans(a+1,b+1,arr[a]))
return dp[a][c]
dp[a][c] = (min(ans(a+1,b,c+arr[a]+1),pow((n-c),2)+ans(a+1,b+1,arr[a])))
return dp[a][c]
print(ans(1,1,3))
阙:https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap
我尝试过的和遇到的问题:我尝试了一种递归方法来解决这个问题。目前,无法找到重叠的子问题。谁能帮助我如何优化、记忆和 modify/update 我的递归方法?。 (我认为我的方法是错误的)
方法: 单词在当前行中(当且仅当 space 被留下时)或者将在新行中。
代码流:
Input text = "Cat is on Floor" .
I stored len in an array = [3,2,2,5]
ans(a,b,c) : a: index, b: line (currently no use), c: current line sum
base condn if all elements are over a>=size: return pow(spaceleft,2)
will return min( subproblem(word in current line),subproblem(word in new line)+pow(spaceleft,2))
Initially : ans(1,1,3)
ans(2,1,6) ans(2,2,2)
ans(3,2,2) ans(3,2,5) ans(3,3,2)
ans(4,3,5) ans(4,3,5) ans(4,4,5)
下面的代码在python3.x:
n=6
arr=[3,2,2,5]
size = 4
def ans(a,b,c):
if(a>=size):
return pow((n-c),2);
if(c+arr[a]+1 > n):
return (pow((n-c),2)+ans(a+1,b+1,arr[a]))
return (min(ans(a+1,b,c+arr[a]+1),pow((n-c),2)+ans(a+1,b+1,arr[a])))
print(ans(1,1,3))
在此先感谢您抽出宝贵的时间帮助我....
我认为您的表述可能遗漏了一些案例。这肯定很难理解。这是一个似乎得到正确答案的答案。
class LineWrapper:
def __init__(self, lens, width):
self.lens = lens
self.width = width;
def cost(self, ptr=0, used=0):
remaining = self.width - used
# Case 1: No words: Cost is due to partially used line.
if ptr == len(self.lens):
return remaining ** 2 if used else 0
# Case 2: First word of line. Must skip.
if used == 0:
return self.cost(ptr + 1, self.lens[ptr])
# Case 3: Out of space. Must wrap.
needed = 1 + self.lens[ptr]
if remaining < needed:
return remaining ** 2 + self.cost(ptr)
# Case 4: Min cost of skip and wrap.
return min(self.cost(ptr + 1, used + needed), remaining ** 2 + self.cost(ptr))
这个公式中的子问题有很多重叠,你的也是。一个简单的示例是宽度为 7 的 [1, 1, 1, 1]。解决方案将尝试将其放在 1、2、3 和 4 行的所有组合上。可能子组合会重复。
为了更清楚地看到这一点,我们可以记忆并检查命中:
def memo_cost(self, ptr=0, used=0):
args = (ptr, used)
print(args)
if args in self.memos:
print(f'Memo hit: {args}')
return self.memos[args]
remaining = self.width - used
# Case 1: No words has cost of partially used line
if ptr == len(self.lens):
r = remaining ** 2 if used else 0
self.memos[args] = r
print(f'Done: {r}')
return r
# Case 2: First word of line. Must skip.
if used == 0:
r = self.memo_cost(ptr + 1, self.lens[ptr])
self.memos[args] = r
print(f'Must skip: {r}')
return r
# Case 3: Out of space. Must wrap.
needed = 1 + self.lens[ptr]
if remaining < needed:
r = remaining ** 2 + self.memo_cost(ptr)
self.memos[args] = r
print(f'Must wrap: {r}')
return r
# Case 4: Min cost of skip wrap and wrap.
r = min(remaining ** 2 + self.memo_cost(ptr), self.memo_cost(ptr + 1, used + needed))
self.memos[args] = r
print(f'Min: {r}')
return r
print(LineWrapper([1, 1, 1, 1], 7).memo_cost())
当 运行 时,会产生:
$ python3 lb.py
(0, 0)
(1, 1)
(1, 0)
(2, 1)
(2, 0)
(3, 1)
(3, 0)
(4, 1)
Done: 36
Must skip: 36
(4, 3)
Done: 16
Min: 16
Must skip: 16
(3, 3)
(3, 0)
Memo hit: (3, 0)
(4, 5)
Done: 4
Min: 4
Min: 4
Must skip: 4
(2, 3)
(2, 0)
Memo hit: (2, 0)
(3, 5)
(3, 0)
Memo hit: (3, 0)
(4, 7)
Done: 0
Min: 0
Min: 0
Min: 0
Must skip: 0
0
感谢@Gene,我的回答带有备忘录
n=7
arr=[3,2,2,5]
INF = 9223372036854775807
size = 4
dp = [[INF for i in range(n+1)] for j in range(size+1)]
def ans(a,b,c):
if(dp[a][c]!=INF):
return dp[a][c]
if(a>=size):
dp[a][c] = pow((n-c),2)
return pow((n-c),2)
if(c+arr[a]+1 > n):
dp[a][c] = (pow((n-c),2)+ans(a+1,b+1,arr[a]))
return dp[a][c]
dp[a][c] = (min(ans(a+1,b,c+arr[a]+1),pow((n-c),2)+ans(a+1,b+1,arr[a])))
return dp[a][c]
print(ans(1,1,3))