【问题标题】:division an integer into k parts将一个整数除为 k 个部分
【发布时间】:2015-06-24 09:07:36
【问题描述】:

我正在用 java 编程,我需要制定一个算法。算法的要求是:

  • 我们有 3 个整数变量nmk
  • 我们想将n 分成k 部分,以便k-parts 的总和 等于n,每个部分都是1m之间的整数。
  • 我们希望所有可能的组合与允许的整数。

以输入集为例:

n = 7; m = 3; k = 4

我们可以制定两种不同的组合:

7 = 2 + 2 + 2 + 1

7 = 3 + 2 + 1 + 1

谢谢大家。

【问题讨论】:

  • 这听起来像是一个 NP 难题。希望有人能说出问题来使您的搜索更容易
  • 您想要“分区”本身还是只希望它们的计数(存在多少分区)?
  • 我不确定这是否完全属于 java 标签。这里的问题更多是算法问题而不是 java 问题。一旦有了算法,java 实现就不应该成为问题
  • @RoelStrolenberg 这不是 NP 难。它甚至不是普通的硬。 :)
  • 你可以用递归解决这个问题。

标签: java algorithm integer-division


【解决方案1】:

这个想法是一种回溯算法方法(带有递归),您可以减少参数并获得部分解决方案,然后检查您是否有正确的解决方案。

public class Problem {

    private static void algorithm(int n, int k, int m) {
        algorithmRecursive(Collections.EMPTY_LIST, n, k, m, 1);
    }

    private static void algorithmRecursive(List<Integer> partial, int n, int k, int m, int min) {
        if ( (k > 0) ) {
            // Optimization
            if ((n <= k * m) && (n >= k*min)){
                for (int i = min; i <= Math.min(m, n); i++) {
                    List<Integer> newPartial = new ArrayList<>(partial);
                    newPartial.add(i);
                    algorithmRecursive(newPartial, n - i, k - 1, m, i);
                }
            }
        } else if (n == 0) {
            // Right solution
            System.out.println(partial);
        }
    }

    public static void main(String[] args) {
        algorithm(7,4,3);
    }
}

【讨论】:

    【解决方案2】:

    要获得“分割数”的计数,您可以使用Dynamic Programming,它遵循递归公式:

    D(0,0,j) = 1
    D(x,0,j) = 0     x > 0
    D(x,i,j) = 0     x < 0 or j<0
    D(x,i,j) = D(x-j,i-1,j) + D(x,i,j-1)
    

    D(n,k,m) 表示的答案是此类划分的数量。
    复杂度是O(n*k*m)

    Java 代码:

    public static int numDivisions(int n, int m, int k) {
        int[][][] D = new int[n+1][k+1][m];
        for (int j = 0; j < m; j++) {
            for (int x = 0; x <= n; x++) {
                D[x][0][j] = 0;
            }
            D[0][0][j] = 1;
        }
        for (int i = 1; i <= k; i++) { 
            for (int x = 0; x <= n; x++) {
                for (int j = 0; j < m; j++) {
                    D[x][i][j] = 0;
                    if (j > 0) D[x][i][j] += D[x][i][j-1];
                    if (x-j-1 >=0) D[x][i][j] += D[x-j-1][i-1][j];
                }
            }
        }
        return D[n][k][m-1];
    }
    

    附带说明,这类似于stars and bars 问题 - 但这里的顺序无关紧要,此外,您对单元格中“星”的数量有上限。

    【讨论】:

      【解决方案3】:

      我相信这可以通过递归轻松完成。先检查n能不能除,也就是n&lt;=m*k &amp;&amp; n&gt;=k的时候,如果不能,返回空数组。

      如果是可整除的,则从[1..m]范围内依次选择m'作为第一个数,然后递归获取其余参数n'=n-'m, m'=m', k'=k-1,然后返回所有结果。

      只有n=0k=0 才能成功停止递归。时间复杂度应该和输出的大小一样。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多