我正在努力理解线性分区问题的动态编程解决方案。我正在阅读《算法设计手册》,第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
第八次递归是:
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
等等…
这是书中显示的代码:
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 */ }
有关算法的问题:
m
d
请注意,本书中对算法的解释有一个小错误,请在勘误表中查找文本“(*)Page 297”。
关于您的问题:
reconstruct_partition
编辑:
这是线性划分算法的实现。它基于Skiena的算法,但是采用Python方式;并返回分区列表。
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)