Algorithm 计算包含k个部分的整数部分,每个部分都低于某个阈值m

Algorithm 计算包含k个部分的整数部分,每个部分都低于某个阈值m,algorithm,math,numbers,combinations,integer-partition,Algorithm,Math,Numbers,Combinations,Integer Partition,我想计算一下我们可以将数字n划分为k不同部分的方法的数量,其中每个部分不大于m 对于k:=2我有以下算法: public int calcIntegerPartition(int n, int k, int m) { int cnt=0; for(int i=1; i <= m;i++){ for(int j=i+1; j <= m; j++){ if(i+j == n){ cnt++; break; }

我想计算一下我们可以将数字
n
划分为
k
不同部分的方法的数量,其中每个部分不大于
m

对于
k:=2
我有以下算法:

public int calcIntegerPartition(int n, int k, int m) {

  int cnt=0;
  for(int i=1; i <= m;i++){
    for(int j=i+1; j <= m; j++){
      if(i+j == n){
        cnt++;
        break;
      }
    }
  }
  return cnt;
}
public整数分解(整数n,整数k,整数m){
int-cnt=0;
对于(int i=1;i 100000
k:=40
m<10000


提前谢谢。

让我们从选择k个最大的法定数字开始:m,m-1,m-2,…,m-(k-1)。这加起来就是k*m-k(k-1)/2。如果m 现在,假设我们从选择k个最大的不同法定整数开始,然后对其进行修正以得到一个解决方案。我们的修正包括将值向左(在数字行上)移动1个槽,移动到空槽中,精确到p次。我们可以用多少种方法来实现这一点

开始时的最小值是m-(k-1),它可以向下移动1次,也可以向上移动m-k次。在此之后,每个连续的值可以向上移动到其前一个值的移动

现在的问题是,有多少个最大值为m-k和p的非递增整数序列?这是划分问题。也就是说,我们可以用多少种方法将p(最多划分为k个分区)。这不是一个封闭形式的解决方案

有人已经在这里写出了这个问题的一个很好的答案(需要稍加修改以满足您的限制):


正如@Dave所暗示的,对于简单的受限整数情况,已经有了一个非常好的答案(在这里可以找到(与@Dave相同的链接):)

下面是
C++
中的一个变体,它考虑了每个受限制部分的最大值。首先,这里是主要部分:

#include <vector>
#include <algorithm>
#include <iostream>

int width;
int blockSize;
static std::vector<double> memoize;

double pStdCap(int n, int m, int myMax) {
    
    if (myMax * m < n || n < m) return 0;
    if (myMax * m == n || n <= m + 1) return 1;
    if (m < 2) return m;
    
    const int block = myMax * blockSize + (n - m) * width + m - 2;
    if (memoize[block]) return memoize[block];
    
    int niter = n / m;
    
    if (m == 2) {
        if (myMax * 2 >= n) {
            myMax = std::min(myMax, n - 1);
            return niter - (n - 1 - myMax);
        } else {
            return 0;
        }
    }
    
    double count = 0;
    
    for (; niter--; n -= m, --myMax) {
        count += (memoize[myMax * blockSize + (n - m) * width + m - 3] = pStdCap(n - 1, m - 1, myMax));
    }
    
    return count;
}
下面是设置递归的函数:

double CountPartLenCap(int n, int m, int myMax) {
    
    if (myMax * m < n || n < m) return 0;
    if (myMax * m == n || n <= m + 1) return 1;
    if (m < 2) return m;
    
    if (m == 2) {
        if (myMax * 2 >= n) {
            myMax = std::min(myMax, n - 1);
            return n / m - (n - 1 - myMax);
        } else {
            return 0;
        }
    }
    
    width = m;
    blockSize = m * (n - m + 1);
    memoize = std::vector<double>((myMax + 1) * blockSize, 0.0);
    
    return pStdCap(n, m, myMax);
}

如果您真的打算为10000个大的数字计算分区数,那么您将需要一个大的int库,如
CountPartLenCap(10000,40,300)>3.2e37
(根据OP的要求)。

谢谢您的解决方案:您的情况是什么:
n,m,myMax,pcount()
?@TThoEinthausend我更新了我的答案。我试图与链接的答案保持一致。如果仍然不清楚,请告诉我。变量
宽度
的赋值从哪里来?你看到了吗?另一个整数分区解释,带有代码:这并不是每个分区在每次分解时的唯一性。我还想知道了解计数。@TThoEinthausend它确实反映了唯一性,链接向您展示了在不枚举解决方案的情况下获取计数的有效方法。
double CountPartLenCap(int n, int m, int myMax) {
    
    if (myMax * m < n || n < m) return 0;
    if (myMax * m == n || n <= m + 1) return 1;
    if (m < 2) return m;
    
    if (m == 2) {
        if (myMax * 2 >= n) {
            myMax = std::min(myMax, n - 1);
            return n / m - (n - 1 - myMax);
        } else {
            return 0;
        }
    }
    
    width = m;
    blockSize = m * (n - m + 1);
    memoize = std::vector<double>((myMax + 1) * blockSize, 0.0);
    
    return pStdCap(n, m, myMax);
}
int pNonMemoStdCap(int n, int m, int myMax) {
    
    if (myMax * m < n) return 0;
    if (myMax * m == n) return 1;
    
    if (m < 2) return m;
    if (n < m) return 0;
    if (n <= m + 1) return 1;
    
    int niter = n / m;
    int count = 0;
    
    for (; niter--; n -= m, --myMax) {
        count += pNonMemoStdCap(n - 1, m - 1, myMax);
    }
    
    return count;
}