【问题标题】:Generating integer partition by its number按其编号生成整数分区
【发布时间】:2013-11-20 19:36:59
【问题描述】:

我正在尝试按字典顺序生成给定整数 N 编号为 K 的体面分区,例如对于N = 5, K = 3,我们得到了:

5 = 1 + 1 + 1 + 1 + 1
5 = 1 + 1 + 1 + 2
5 = 1 + 1 + 3
5 = 1 + 2 + 2
5 = 1 + 4
5 = 2 + 3
5 = 5

第三个是1 + 1 + 3。 如何在不生成每个分区的情况下生成它(用 C 语言,但最重要的是我需要算法)?

要找到分区中的最大数(假设我们可以找到分区数d[i][j],其中i 是数字,j 是其分区中的最大整数),然后减少我们正在寻找的原始数字和数字为了。所以是的,我正在尝试使用动态编程。仍在编写代码。

这根本不起作用:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


FILE *F1, *F2;


main()
{
    long long i, j, p, n, k, l, m[102][102];
    short c[102];
    F1 = fopen("num2part.in", "r");
    F2 = fopen ("num2part.out", "w");
    n = 0;
    fscanf (F1, "%lld %lld", &n, &k);
    p = 0;
    m[0][0] = 1;
    for ( i = 0; i <= n; i++)
    {
        for (j = 1; j <= i; j++)
        {
            m[i][j] = m[i - j][j] + m[i][j - 1];
        }
        for (j = i + 1; j <= n; j++)
        {
            m[i][j] = m[i][i];
        }
    }
    l = n;
    p = n;
    j = n;
    while (k > 0)
    {
        while ( k < m[l][j])
        {
            if (j == 0)
            {
                while (l > 0)
                {
                    c[p] = 1;
                    p--;
                    l--;
                }
            break;
        }
        j--;
    }
    k -=m[l][j];
    c[p] = j + 1;
    p--;
    l -= c[p + 1];
    }
//printing answer here, answer is contained in array from c[p] to c[n]
}

【问题讨论】:

  • 使用动态规划找到 n
  • 尝试在分区中找到最大数量(假设我们可以找到分区数量d[i][j],其中i是数字,j是其分区中的最大整数),然后减少原始数量和我们正在寻找的号码,仍在努力。

标签: algorithm integer-partition


【解决方案1】:

以下是一些生成分区的示例 Python 代码:

cache = {}
def p3(n,val=1):
    """Returns number of ascending partitions of n if all values are >= val"""
    if n==0:
        return 1 # No choice in partitioning
    key = n,val
    if key in cache:
        return cache[key]
    # Choose next value x
    r = sum(p3(n-x,x) for x in xrange(val,n+1))
    cache[key]=r
    return r

def ascending_partition(n,k):
    """Generate the k lexicographically ordered partition of n into integer parts"""
    P = []
    val = 1 # All values must be greater than this
    while n:
        # Choose the next number
        for x in xrange(val,n+1):
            count = p3(n-x,x)
            if k >= count:
                # Keep trying to find the correct digit
                k -= count
            elif count: # Check that there are some valid positions with this digit
                # This must be the correct digit for this location
                P.append(x)
                n -= x
                val = x
                break
    return P

n=5
for k in range(p3(n)):
    print k,ascending_partition(n,k)

打印出来:

0 [1, 1, 1, 1, 1]
1 [1, 1, 1, 2]
2 [1, 1, 3]
3 [1, 2, 2]
4 [1, 4]
5 [2, 3]
6 [5]

这可用于生成任意分区,而无需生成所有中间分区。比如有9253082936723602个分区300个。

print ascending_partition(300,10**15)

打印

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 5, 7, 8, 8, 11, 12, 13, 14, 14, 17, 17, 48, 52]

【讨论】:

  • 谢谢,我有生成所有分区的代码,但是应该有解决方案可以按这个顺序生成一个数量合适的分区(生成所有的工作太慢)。
  • 这里的代码一次生成一个分区。您可以简单地使用所需的 n 和 k 值调用ascending_partition(n,k)。我只是在循环中进行测试。
  • 这仍然需要处理所有分区的开销,对吧? (而不是简单地计算所需的)
  • @Dukeling 不,我认为复杂度大致为 O(n^3) 并且不依赖于 k。该示例显示它几乎立即为 k 的巨大值计算分区。
【解决方案2】:
def _yieldParts(num,lt):
  ''' It generate a comination set'''
  if not num:
    yield ()
  for i in range(min(num,lt),0,-1):
    for parts in _yieldParts(num-i,i):
      yield (i,)+parts


def patition(number,kSum,maxIntInTupple):
  ''' It generates a comination set with sum of kSum is equal to number
      maxIntInTupple is for maximum integer can be in tupple'''
  for p in _yieldParts(number,maxIntInTupple):
    if(len(p) <=kSum):
      if(len(p)<kSum):
        while len(p) < kSum:
          p+=(0,)
      print p


patition(40,8,40)

Output:
-------
(40,0,0,0,0,0,0,0)
(39,1,0,0,0,0,0,0)
. 
.
.
.

【讨论】:

  • 解释你的代码。仅代码答案不受欢迎。
  • 我已经给出了 cmets 的功能。你可以得到一些想法。
猜你喜欢
  • 2012-05-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-10
  • 2017-09-14
  • 2022-09-27
  • 1970-01-01
  • 1970-01-01
  • 2020-01-27
相关资源
最近更新 更多