gpt4 book ai didi

algorithm - 如何理解线性划分中的动态规划解法?

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:14:47 25 4
gpt4 key购买 nike

我正在努力理解线性分区问题的动态规划解决方案。我正在阅读 Algorithm Design Manual问题在 8.5 节中描述。我已经无数次阅读该部分,但我就是不明白。我认为这是一个糟糕的解释(到目前为止我读到的内容要好得多),但我无法很好地理解问题以寻找替代解释。欢迎链接到更好的解释!

我找到了一个页面,其中的文字与本书相似(可能来自本书的第一版):The Partition Problem .

第一个问题:书上的例子中分区是从小到大排序的。这只是巧合吗?据我所知,元素的顺序对算法并不重要。

这是我对递归的理解:

让我们使用以下序列并将其分成 4 个:

{S1...Sn} =  100   150   200   250   300   350   400   450   500
k = 4

第二个问题:这是我认为递归将如何开始的 - 我是否理解正确?

第一个递归是:

100   150   200   250   300   350   400   450 | 500 //3 partition to go
100 150 200 250 300 350 400 | 450 | 500 //2 partition to go
100 150 200 250 300 350 | 400 | 450 | 500 //1 partition to go
100 150 200 250 300 | 350 | 400 | 450 | 500 //done

第二次递归是:

100   150   200   250   300   350   400   450 | 500 //3 partition to go
100 150 200 250 300 350 400 | 450 | 500 //2 partition to go
100 150 200 250 300 350 | 400 | 450 | 500 //1 partition to go
100 150 200 250 | 300 350 | 400 | 450 | 500 //done

第三个递归是:

100   150   200   250   300   350   400   450 | 500 //3 partition to go
100 150 200 250 300 350 400 | 450 | 500 //2 partition to go
100 150 200 250 300 350 | 400 | 450 | 500 //1 partition to go
100 150 200 | 250 300 350 | 400 | 450 | 500 //done

第四次递归是:

100   150   200   250   300   350   400   450 | 500 //3 partition to go
100 150 200 250 300 350 400 | 450 | 500 //2 partition to go
100 150 200 250 300 350 | 400 | 450 | 500 //1 partition to go
100 150 | 200 250 300 350 | 400 | 450 | 500 //done

第五次递归是:

100   150   200   250   300   350   400   450 | 500 //3 partition to go
100 150 200 250 300 350 400 | 450 | 500 //2 partition to go
100 150 200 250 300 350 | 400 | 450 | 500 //1 partition to go
100 | 150 200 250 300 350 | 400 | 450 | 500 //done

第六次递归是:

100   150   200   250   300   350   400   450 | 500 //3 partition to go
100 150 200 250 300 350 400 | 450 | 500 //2 partition to go
100 150 200 250 300 | 350 400 | 450 | 500 //1 partition to go
100 150 200 250 | 300 | 350 400 | 450 | 500 //done

第七次递归是:

100   150   200   250   300   350   400   450 | 500 //3 partition to go
100 150 200 250 300 350 400 | 450 | 500 //2 partition to go
100 150 200 250 300 | 350 400 | 450 | 500 //1 partition to go
100 150 200 | 250 300 | 350 400 | 450 | 500 //done

第 8 次递归是:

100   150   200   250   300   350   400   450 | 500 //3 partition to go
100 150 200 250 300 350 400 | 450 | 500 //2 partition to go
100 150 200 250 300 | 350 400 | 450 | 500 //1 partition to go
100 150 | 200 250 300 | 350 400 | 450 | 500 //done

第 9 次递归是:

100   150   200   250   300   350   400   450 | 500 //3 partition to go
100 150 200 250 300 350 400 | 450 | 500 //2 partition to go
100 150 200 250 300 | 350 400 | 450 | 500 //1 partition to go
100 | 150 200 250 300 | 350 400 | 450 | 500 //done

等...

这是书中出现的代码:

partition(int s[], int n, int k)
{
int m[MAXN+1][MAXK+1]; /* DP table for values */
int d[MAXN+1][MAXK+1]; /* DP table for dividers */
int p[MAXN+1]; /* prefix sums array */
int cost; /* test split cost */
int i,j,x; /* counters */

p[0] = 0; /* construct prefix sums */
for (i=1; i<=n; i++) p[i]=p[i-1]+s[i];

for (i=1; i<=n; i++) m[i][3] = p[i]; /* initialize boundaries */
for (j=1; j<=k; j++) m[1][j] = s[1];


for (i=2; i<=n; i++) /* evaluate main recurrence */
for (j=2; j<=k; j++) {
m[i][j] = MAXINT;
for (x=1; x<=(i-1); x++) {
cost = max(m[x][j-1], p[i]-p[x]);
if (m[i][j] > cost) {
m[i][j] = cost;
d[i][j] = x;
}
}
}

reconstruct_partition(s,d,n,k); /* print book partition */
}

关于算法的问题:

  1. md 中存储了什么值?
  2. “成本”是什么意思?它只是分区内元素值的总和吗?还是有其他更微妙的含义?

最佳答案

注意书上对算法的解释有点小错误,看errata对于文本“(*) 第 297 页”。

关于您的问题:

  1. 不,项目不需要排序,只是连续的(也就是说,你不能重新排列它们)
  2. 我认为可视化算法的最简单方法是手动跟踪 reconstruct_partition 过程,使用图 8.8 中最右边的表作为指南
  3. 在书中它指出 m[i][j] 是“将 {s1, s2, ... , si} 的所有分区的最小可能成本”分成 j 个范围,其中分区的成本是它的一个部分中元素的大和”。换句话说,如果您原谅滥用术语,它是“总和的最小最大值”。另一方面,d[i][j] 存储索引位置,它是用于为之前定义的给定对 i,j 进行分区
  4. “成本”的含义,见上一个回答

编辑:

这是我对线性分区算法的实现。它基于 Skiena 的算法,但采用了 pythonic 方式;并返回分区列表。

from operator import itemgetter

def linear_partition(seq, k):
if k <= 0:
return []
n = len(seq) - 1
if k > n:
return map(lambda x: [x], seq)
table, solution = linear_partition_table(seq, k)
k, ans = k-2, []
while k >= 0:
ans = [[seq[i] for i in xrange(solution[n-1][k]+1, n+1)]] + ans
n, k = solution[n-1][k], k-1
return [[seq[i] for i in xrange(0, n+1)]] + ans

def linear_partition_table(seq, k):
n = len(seq)
table = [[0] * k for x in xrange(n)]
solution = [[0] * (k-1) for x in xrange(n-1)]
for i in xrange(n):
table[i][0] = seq[i] + (table[i-1][0] if i else 0)
for j in xrange(k):
table[0][j] = seq[0]
for i in xrange(1, n):
for j in xrange(1, k):
table[i][j], solution[i-1][j-1] = min(
((max(table[x][j-1], table[i][0]-table[x][0]), x) for x in xrange(i)),
key=itemgetter(0))
return (table, solution)

关于algorithm - 如何理解线性划分中的动态规划解法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7938809/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com