Hier ist ein Lösungsvorschlag.
Ich löse zuerst ein erstes Teilproblem: Ich nehme an, dass alle Zahlen und das Ziel positive Zahl sind, dann löse ich das wirkliche Problem.
Um dies zu erreichen, zerlege ich das Problem im Grunde in Teilprobleme.
Beginnen wir mit einem Beispiel illustrieren:
Zahlen: 1,3,8,2,7 Ziel: 10
Erstens: sortieren Sie die Liste: Zahlen: 8,7,3,2,1 Ziel: 10 Dann rekursiv die Lösungen zu den folgenden Problemen finden:
Numbers: 7,3,2,1 target: 10-8 = 2
Numbers: 3,2,1 target: 10-7 = 3
Zahlen: 2,1 Target: 10-3 = 2
Zahlen: 1 Target: 10-1 = 9
Ziel vor große Zahlen des Vergebens schnell Lösungen zu beseitigen, diese Nummer einschließlich (weil die Summe überschreitet schnell das Ziel). Hier
ist der kommentierten Code für die Auflösung dieses Teilproblem:
import java.util.ArrayList;
import java.util.List;
public class Problem {
/*
* Used at the end to recompose the solutions.
* This value is null for the root problem.
*/
private Integer nodeValue;
//The POSITIVE target sum
private int target;
//List of POSITIVE numbers, supposed to be sorted
private List<Integer> numbers;
private List<Problem> listSubProblems;
/*
* Link to the parent problem.
* Useful at the end to generate the results.
*/
private Problem parentProblem;
public Problem(int target, List<Integer> numbers, Integer nodeValue, Problem parentProblem){
this.target=target;
this.numbers=numbers;
this.nodeValue=nodeValue;
this.parentProblem=parentProblem;
this.listSubProblems =new ArrayList<Problem>();
}
public void solve(){
buildSubProblems();
for(Problem problem : listSubProblems){
problem.solve();
}
}
/**
* Builds a List of sub problems.
* For example, if {@link #numbers} contains 9 8 5 3, with target 10
* this method will return the following sub problems:
*
* <table>
* <tr>
* <td>nodeValue</td><td>target</td><td>numbers</td>
* </tr>
* <tr>
* <td>9</td><td>10-9=1</td><numbers>8 5 3</numbers>
* </tr>
* <tr>
* <td>8</td><td>10-8=2</td><numbers>5 3</numbers>
* </tr>
* <tr>
* <td>5</td><td>10-5=5</td><numbers>3</numbers>
* </tr>
*
* </table>
*
*/
private void buildSubProblems(){
int numbersSize=numbers.size();
/*
* Numbers are supposed to be positive so if the target is negative,
* there is no chance to find a valid solution.
* As the list of numbers is sorted, the case when target < 0 happens quickly
* Hence, it quickly removes combinations implying big numbers
*/
if(target>=0 && numbersSize> 1){
for(int i=0;i<numbersSize;i++){
Integer nodeValue=numbers.get(i);
List<Integer> subList=numbers.subList(i+1,numbersSize);
int newTarget=this.target-nodeValue;
Problem problem=new Problem(newTarget, subList, nodeValue, this);
System.out.println("Created problem: "+problem.dump());
this.listSubProblems.add(problem);
}
}
}
/**
* @return True is the Problem contains exactly one number and that number equals the target.
*/
public boolean isNodeSolution(){
return this.target==0;
}
public Integer getNodeValue(){
return this.nodeValue;
}
public List<Problem> getListSubProblems(){
return this.listSubProblems;
}
public Problem getParentProblem(){
return this.parentProblem;
}
public String dump(){
StringBuilder sb=new StringBuilder();
sb.append("{nodeValue: "+this.nodeValue);
sb.append("; target: "+target);
sb.append("; numbers:");
for(Integer integer : numbers){
sb.append(integer+",");
}
sb.append("}");
sb.append("Valid? : "+ isNodeSolution());
return sb.toString();
}
}
Hier ist der Code, der zeigt, wie es testen:
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) throws Exception{
Integer numbers[]={1,3,8,2,7};
int target=10;
List<Integer> listNumbers= Arrays.asList(numbers);
Collections.sort(listNumbers);
Collections.reverse(listNumbers);
//Build the root problem
Problem problem=new Problem(target,listNumbers,null,null);
//Solve it
problem.solve();
//Dump the result.
dumpResult(problem);
System.out.println("Done!");
}
private static void dumpResult(Problem problem){
for(Problem p:problem.getListSubProblems()){
if(p.isNodeSolution()){
System.out.print("\nSolution :");
dumpSolution(p);
}
dumpResult(p);
}
}
private static void dumpSolution(Problem problem){
//If the current node is not the root problem
if(problem.getParentProblem()!=null){
System.out.print(problem.getNodeValue() + ", ");
dumpSolution(problem.getParentProblem());
}
}
}
Und hier ist ein Beispiel für Ausgang :
Created problem: {nodeValue: 8; target: 2; numbers:7,3,2,1,}Valid? : false
Created problem: {nodeValue: 7; target: 3; numbers:3,2,1,}Valid? : false
Created problem: {nodeValue: 3; target: 7; numbers:2,1,}Valid? : false
Created problem: {nodeValue: 2; target: 8; numbers:1,}Valid? : false
Created problem: {nodeValue: 1; target: 9; numbers:}Valid? : false
Created problem: {nodeValue: 7; target: -5; numbers:3,2,1,}Valid? : false
Created problem: {nodeValue: 3; target: -1; numbers:2,1,}Valid? : false
Created problem: {nodeValue: 2; target: 0; numbers:1,}Valid? : true
Created problem: {nodeValue: 1; target: 1; numbers:}Valid? : false
Created problem: {nodeValue: 3; target: 0; numbers:2,1,}Valid? : true
Created problem: {nodeValue: 2; target: 1; numbers:1,}Valid? : false
Created problem: {nodeValue: 1; target: 2; numbers:}Valid? : false
Created problem: {nodeValue: 2; target: -2; numbers:1,}Valid? : false
Created problem: {nodeValue: 1; target: -1; numbers:}Valid? : false
Created problem: {nodeValue: 2; target: 5; numbers:1,}Valid? : false
Created problem: {nodeValue: 1; target: 6; numbers:}Valid? : false
Solution :2, 8,
Solution :3, 7, Done!
Nun, dies deckt nicht das anfängliche Problem, das negative Zahlen impliziert. Um diesen Fall zu lösen, isoliere alle negativen Zahlen und berechne alle Kombinationen negativer Zahlen mit ihrer Summe.
Dann wird für jede Summe negative Zahl, erstellen Sie ein Teilproblem nur positive Zahlen und ein entsprechendes Ziel (ursprüngliche Ziel - Summe der negativen Zahlen), die
Ein Weg, um es zu verbessern: Die Komplexität der Probleme hängt auf die Anzahl der Kombinationen von negativen Zahlen. Wenn also mehr negative als positive Zahlen vorhanden sind, können Sie einfach alle Werte invertieren und das Invertierungsproblem lösen.
Eine andere Möglichkeit, es zu verbessern: Sie können die Summe der positiven Zahlen jedes Teilproblems im Speicher behalten. Wenn sum + nodeValue < Ziel ist, dann ist es nutzlos, den Zweig weiter zu erkunden.
etwas macht mich will denken, dass dies ein np schweres Problem ist, aber ich weiß nicht, was –
Schade, dass dies nicht mit C# markiert ist. Ich war im Begriff, 'var result = aus der Teilmenge in input.PowerSet() zu referieren, wobei subset.Sum() == 0 select subset;' – dtb
es hat eine endliche Lösung mit einer endlichen Eingabe ... aber es ist ich denke O (n!^3) - oder etwas ähnliches hässliches .. – Randy