簡體   English   中英

回溯 - 給定一組數字,找到總和等於 M 的所有子集(給定 M)

[英]Backtracking - Given a set of numbers, find all the subsets with a sum equal to M (M is given)

正如標題所說,我們得到一組數字,我們必須找到總和等於給定數字的所有子集(我們稱之為 M)。

你們中的大多數人可能已經熟悉這個問題,所以讓我們切入正題。 我最近才開始回溯編程(我得告訴你,到目前為止我是一個徹頭徹尾的人),這就是為什么我試圖解決更“經典”的問題。

現在,在下面你會看到我的代碼,它試圖以回溯的方式解決這個問題。 但是,代碼給出

線程“main”中的異常 java.lang.StackOverflowError

在第 44 行(我將突出顯示它)而且,我真的不知道它是否真的以回溯的方式解決了問題,或者我的代碼是否只是完整的和完全的便便。

package project3;

import java.util.*;

public class Main {
    static int[] A = { 1, 2, 3, 4 }; // the array in which we are given the numbers.->
    static int n = A.length;  // -> I have it filled with 1, 2, 3, 4 for testing purposes
    static int m = 5;  // the number which the subsets' sum must be
    static int[] Sol = new int[50];  // the array in which solutions are stored up-> 
                            //->until they are syso'ed, after that it gets zero'ed
    static void makeZero() {          // make the solution array 0 again
        for (int i = 0; i < 50; i++)
            Sol[i] = 0;
    }

    static void show() {  // outputs the solution array
        int i = 0;
        while (Sol[i] != 0 && i < 49) {
            System.out.print(Sol[i] + " ");
            i++;
        }
    }

    public static void main(String[] args) {
        Sol[0]=A[0]; back(0, 1, A[0], 1);// we start with the first number in the array as->
    }                        // -> both the first element as the solution and part of the sum

    static int back(int i, int j, int S, int nr) {
        if (i < n && j < n) {

            if (A[j] + S == m) {// if we got a solution, we output it and then go to the ->
                Sol[nr] = A[j]; // -> next element if possible, if not, we start again with ->
                show();         // -> the following element
                if (j < n - 1)
                    back(i, j++, S, nr);
                else if (i < n - 1) {
                    makeZero();
                    back(i + 1, i + 2, 0, 0);
                }
            }

            else if (A[j] + S > m) {  // condition for stoping and starting over with another element
                if (j < n - 1)  // we try again with the following element
                    back(i, j++, S, nr);// LINE 44 : Exception in thread "main" java.lang.StackOverflowError
                else if (i < n - 2 && j == n - 1) { // if not possible, we start again with the following element
                    makeZero();
                    back(i + 1, i + 2, 0, 0);
                } else if (i == n - 2 && j == n - 1)  // if we are down to the last element-> 
                    if (A[i + 1] == m)             // ->we check if it is ==m
                        System.out.println(A[i + 1]);
                }


            else if (j < n - 1 && A[j] + S < m) {  // obvious
                Sol[nr++] = A[j];
                S = S + A[j];
                back(i, j + 1, S, nr);
            }

            else if (j == n - 1 && A[j] + S < m && i < n - 2) {// if the sum!=m and the are no more elements-> 
                makeZero();                                   // ->start again with another element
                back(i + 1, i + 2, 0, 0);
            }
            else { // if we are down to the last element, we check if it is ==m
                if(A[i+1]==n-1)
                    System.out.println(A[i + 1]);
            }

        }

        return 0;
    }

}

注意:我希望我的評論有用,但如果它們比幫助忽略它們更令人困惑,我認為您可以了解沒有它們我在做什么。

盡管如此,我想找出代碼給出該錯誤的原因(我確實知道在什么情況下通常會給出該錯誤,但我不明白為什么我在這里得到它,因為我看不到任何無限循環) 以及如何使代碼工作,以及它是否正在回溯。

為了在不出現堆棧溢出錯誤的情況下找到所有子集,我強烈建議不要使用遞歸。 使用遞歸通常會在運行時產生大量開銷。 這種開銷會導致堆棧溢出錯誤。 您應該使用更穩定的算法方法/設計,稱為動態規划。

動態編程示例應該向您展示如何獲取您當前擁有的內容並將其轉換為動態編程概念。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM