对具有 k 个部分的整数分区进行排序和取消排序
Rank and unrank integer partition with k parts
对于正整数n和k,设一个“k-划分n" 是 k 个不同正整数的排序列表,加起来等于 n,并让 "rank" 的给定 k - n 的分区是它在所有这些列表的排序列表中的位置,从字典顺序开始0.
例如,有两个 2-partition of 5 (n = 5, k = 2): [1,4 ] 和 [2,3]。由于 [1,4] 按字典顺序排在 [2,3] 之前,因此 [1,4] 的等级为 0 而 [2,3] 的等级为 1.
所以,我希望能够做两件事:
- 给定 n、k 和 k 的 k-分区]n,我想找到 k-partition of n.
的秩
- 给定 n、k 和一个排名,我想找到 k -n 具有该级别的分区。
我可以这样做而不必计算 n 的所有 k 分区,这些分区在感兴趣的分区之前吗?
这个问题与其他问题不同,因为我们在这里讨论的是整数分区,而不仅仅是组合。
Python 中的解决方案依赖于两个想法。首先,动态规划计算分区而不生成它们。其次,如果第一个值是 i
那么我们可以将其视为一个 i * k
盒子,其中 n-i*k
分成 k-1
块放在顶部。
partition_cache = {}
def distinct_partition_count (n, k):
if n < k:
return 0
elif n < 1:
return 0
elif k < 1:
return 0
elif k == 1:
return 1
elif (n, k) not in partition_cache:
answer = 0
for i in range(1, n/k + 1):
answer = answer + distinct_partition_count(n - i*k, k-1)
partition_cache[(n, k)] = answer
return partition_cache[(n, k)]
def rank_distinct_partition (values):
values2 = sorted(values)
n = sum(values)
k = len(values)
answer = 0
highwater = 0
for v in values:
rise = v - highwater
for i in range(1, rise):
answer = answer + distinct_partition_count(n - k*i, k-1)
highwater = v
## BUG HERE: was n = n - rise
n = n - rise * k
k = k - 1
return answer
def find_ranked_distinct_partition (n, k, rank):
if k == 1 and rank == 0:
return [n]
elif distinct_partition_count(n, k) <= rank:
return None
elif rank < 0:
return None
else:
i = 1
while distinct_partition_count(n - i*k, k-1) <= rank:
rank = rank - distinct_partition_count(n - i*k, k-1);
i = i + 1
answer = find_ranked_distinct_partition(n - i*k, k-1, rank)
return [i] + [j + i for j in answer]
print(rank_distinct_partition([2, 3])
print(find_ranked_distinct_partition(5, 2, 1))
对于正整数n和k,设一个“k-划分n" 是 k 个不同正整数的排序列表,加起来等于 n,并让 "rank" 的给定 k - n 的分区是它在所有这些列表的排序列表中的位置,从字典顺序开始0.
例如,有两个 2-partition of 5 (n = 5, k = 2): [1,4 ] 和 [2,3]。由于 [1,4] 按字典顺序排在 [2,3] 之前,因此 [1,4] 的等级为 0 而 [2,3] 的等级为 1.
所以,我希望能够做两件事:
- 给定 n、k 和 k 的 k-分区]n,我想找到 k-partition of n. 的秩
- 给定 n、k 和一个排名,我想找到 k -n 具有该级别的分区。
我可以这样做而不必计算 n 的所有 k 分区,这些分区在感兴趣的分区之前吗?
这个问题与其他问题不同,因为我们在这里讨论的是整数分区,而不仅仅是组合。
Python 中的解决方案依赖于两个想法。首先,动态规划计算分区而不生成它们。其次,如果第一个值是 i
那么我们可以将其视为一个 i * k
盒子,其中 n-i*k
分成 k-1
块放在顶部。
partition_cache = {}
def distinct_partition_count (n, k):
if n < k:
return 0
elif n < 1:
return 0
elif k < 1:
return 0
elif k == 1:
return 1
elif (n, k) not in partition_cache:
answer = 0
for i in range(1, n/k + 1):
answer = answer + distinct_partition_count(n - i*k, k-1)
partition_cache[(n, k)] = answer
return partition_cache[(n, k)]
def rank_distinct_partition (values):
values2 = sorted(values)
n = sum(values)
k = len(values)
answer = 0
highwater = 0
for v in values:
rise = v - highwater
for i in range(1, rise):
answer = answer + distinct_partition_count(n - k*i, k-1)
highwater = v
## BUG HERE: was n = n - rise
n = n - rise * k
k = k - 1
return answer
def find_ranked_distinct_partition (n, k, rank):
if k == 1 and rank == 0:
return [n]
elif distinct_partition_count(n, k) <= rank:
return None
elif rank < 0:
return None
else:
i = 1
while distinct_partition_count(n - i*k, k-1) <= rank:
rank = rank - distinct_partition_count(n - i*k, k-1);
i = i + 1
answer = find_ranked_distinct_partition(n - i*k, k-1, rank)
return [i] + [j + i for j in answer]
print(rank_distinct_partition([2, 3])
print(find_ranked_distinct_partition(5, 2, 1))