Loading military units into ships optimally, using backtrackingSolving Sudoku using backtrackingIs this a true backtracking algorithm?Sudoku solutions finder using brute force and backtrackingn-Queens backtracking codePartitions of a number (backtracking) - time efficiencyPuzzle game solver via BacktrackingBacktracking maze traversalSimple backtracking codeN Queens in Python using backtracking
Is there a way to unplug the Raspberry pi safely without shutting down
Is Texas Instrument wrong with their pin number on TO-92 package?
How does "Te vas a cansar" mean "You're going to get tired"?
Is it okay for a ticket seller to grab a tip in the USA?
Does a code snippet compile? Or does it get compiled?
what is measured in units of sat/kw?
Ex-contractor published company source code and secrets online
Write an interpreter for *
During the Space Shuttle Columbia Disaster of 2003, Why Did The Flight Director Say, "Lock the doors."?
Should I ask for permission to write an expository post about someone's else research?
(11 of 11: Meta) What is Pyramid Cult's All-Time Favorite?
Withdrew when Jimmy met up with Heath
Generate Brainfuck for the numbers 1–255
I accidentally overwrote a Linux binary file
What are the uses and limitations of Persuasion, Insight, and Deception against other PCs?
What does Apple mean by "This may decrease battery life"?
How many different ways are there to checkmate in the early game?
Why isn’t SHA-3 in wider use?
DeclareMathOperator and widearcarrow with kpfonts
Multirow in tabularx?
What game uses dice with sides powers of 2?
Loading military units into ships optimally, using backtracking
Help evaluating integral (anything simple that I am missing?)
What is the difference between 型 and 形?
Loading military units into ships optimally, using backtracking
Solving Sudoku using backtrackingIs this a true backtracking algorithm?Sudoku solutions finder using brute force and backtrackingn-Queens backtracking codePartitions of a number (backtracking) - time efficiencyPuzzle game solver via BacktrackingBacktracking maze traversalSimple backtracking codeN Queens in Python using backtracking
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
$begingroup$
I solved the following problem using backtracking:
We are given a list of military units, their weight and their
(numerical) strength. We have a number of ships with a limited
carrying capacity. Determine how to load ships with military units, so
that carrying capacity for each ship is not exceed and so that we have
the maximum possible military strength on our ships.
However, my code is not fast enough, as there are many unnecessary calculations being done, that does not lead to a solution. How would I optimize my code? My idea is to use memoization, but how would I implement it?
I tried to comment my code and refactor my code as best as I can.
public class HeroesOntTheBoat {
private int[] arrayWithGeneratedNumbers;
private int numberOfShips;
private int max;
private int[] bestArray;
private ArrayList<Integer> strengths;
private ArrayList<Integer> weights;
private ArrayList<Integer> carryingCapacities;
public HeroesOntTheBoat()
carryingCapacities = new ArrayList<Integer>(); // create arraylist for the carrying capacities of ships
strengths = new ArrayList<Integer>(); //create arraylists for strengths and weights of units
weights = new ArrayList<Integer>(); //create arraylists for weights
max = 0; // global variable max for finding the best strength
private void generate(int fromIndex) // I generate all combinations between 0 and numberOfShips
if (fromIndex == arrayWithGeneratedNumbers.length) // 0 is representing that unit is being left behind
processGeneratedNumbers(); // 1,2,3,4..n are representing the number of ship that the unit is loaded on
return; // index of a number in array is representing a specific unit
for (int i = 0; i <= numberOfShips; i++)
arrayWithGeneratedNumbers[fromIndex] = i;
generate(fromIndex + 1);
public void input(String input)
Scanner sc = null;
try
sc = new Scanner(new File(input)); // load my input from a textfile
numberOfShips = sc.nextInt(); // load the number of ships
for (int i = 0; i < numberOfShips; i++) //add carrying capacities to arraylist
carryingCapacities.add(sc.nextInt());
bestArray = new int[weights.size()]; // array where we will remember the best combination of units
while (sc.hasNext())
weights.add(sc.nextInt());
strengths.add(sc.nextInt());
arrayWithGeneratedNumbers = new int[weights.size()]; // array where we will generate numbers
generate(0); // run the generation
System.out.println(Arrays.toString(bestArray) + " this is the best layout of units"); // after the generation is over
System.out.println(max + " this is the max strength we can achieve"); // print the results
catch (FileNotFoundException e)
System.err.println("FileNotFound");
finally
if (sc != null)
sc.close();
public void processGeneratedNumbers()
int currentStrength = 0; // process every generated result
boolean carryingCapacityWasExceeded = false;
int[] currentWeight = new int[numberOfShips + 1];
for (int i = 0; i < arrayWithGeneratedNumbers.length; i++) // calculate weights for every ship and ground
currentWeight[arrayWithGeneratedNumbers[i]] += weights.get(i);
for (int i = 0; i < currentWeight.length; i++) // is capacity exceeded?
if (i != 0 && currentWeight[i] > carryingCapacities.get(i - 1)) // ignore 0, because 0 represents ground(units I left behind)
carryingCapacityWasExceeded = true;
if (carryingCapacityWasExceeded == false) // if capacity isn't exceeded
for (int i = 0; i < arrayWithGeneratedNumbers.length; i++) // calculate strength
if (arrayWithGeneratedNumbers[i] != 0) // ignore 0, because I left units with 0 behind on the ground
currentStrength += strengths.get(i);
if (currentStrength > max) // is my current strength better than global maximum?
max = currentStrength; // replace my global maximum
bestArray = arrayWithGeneratedNumbers.clone(); // remember the new best layout of units
public static void main(String[] args)
HeroesOnTheBoat g = new HeroesOnTheBoat();
g.input("inputFile");
Example input:
2 60 40
30 400
20 500
50 100
40 100
30 50
60 75
40 20
and its result:
[1, 1, 0, 2, 0, 0, 0] this is the best layout of units
1000 this is the max strength we can achieve
java recursion time-limit-exceeded backtracking knapsack-problem
New contributor
$endgroup$
add a comment |
$begingroup$
I solved the following problem using backtracking:
We are given a list of military units, their weight and their
(numerical) strength. We have a number of ships with a limited
carrying capacity. Determine how to load ships with military units, so
that carrying capacity for each ship is not exceed and so that we have
the maximum possible military strength on our ships.
However, my code is not fast enough, as there are many unnecessary calculations being done, that does not lead to a solution. How would I optimize my code? My idea is to use memoization, but how would I implement it?
I tried to comment my code and refactor my code as best as I can.
public class HeroesOntTheBoat {
private int[] arrayWithGeneratedNumbers;
private int numberOfShips;
private int max;
private int[] bestArray;
private ArrayList<Integer> strengths;
private ArrayList<Integer> weights;
private ArrayList<Integer> carryingCapacities;
public HeroesOntTheBoat()
carryingCapacities = new ArrayList<Integer>(); // create arraylist for the carrying capacities of ships
strengths = new ArrayList<Integer>(); //create arraylists for strengths and weights of units
weights = new ArrayList<Integer>(); //create arraylists for weights
max = 0; // global variable max for finding the best strength
private void generate(int fromIndex) // I generate all combinations between 0 and numberOfShips
if (fromIndex == arrayWithGeneratedNumbers.length) // 0 is representing that unit is being left behind
processGeneratedNumbers(); // 1,2,3,4..n are representing the number of ship that the unit is loaded on
return; // index of a number in array is representing a specific unit
for (int i = 0; i <= numberOfShips; i++)
arrayWithGeneratedNumbers[fromIndex] = i;
generate(fromIndex + 1);
public void input(String input)
Scanner sc = null;
try
sc = new Scanner(new File(input)); // load my input from a textfile
numberOfShips = sc.nextInt(); // load the number of ships
for (int i = 0; i < numberOfShips; i++) //add carrying capacities to arraylist
carryingCapacities.add(sc.nextInt());
bestArray = new int[weights.size()]; // array where we will remember the best combination of units
while (sc.hasNext())
weights.add(sc.nextInt());
strengths.add(sc.nextInt());
arrayWithGeneratedNumbers = new int[weights.size()]; // array where we will generate numbers
generate(0); // run the generation
System.out.println(Arrays.toString(bestArray) + " this is the best layout of units"); // after the generation is over
System.out.println(max + " this is the max strength we can achieve"); // print the results
catch (FileNotFoundException e)
System.err.println("FileNotFound");
finally
if (sc != null)
sc.close();
public void processGeneratedNumbers()
int currentStrength = 0; // process every generated result
boolean carryingCapacityWasExceeded = false;
int[] currentWeight = new int[numberOfShips + 1];
for (int i = 0; i < arrayWithGeneratedNumbers.length; i++) // calculate weights for every ship and ground
currentWeight[arrayWithGeneratedNumbers[i]] += weights.get(i);
for (int i = 0; i < currentWeight.length; i++) // is capacity exceeded?
if (i != 0 && currentWeight[i] > carryingCapacities.get(i - 1)) // ignore 0, because 0 represents ground(units I left behind)
carryingCapacityWasExceeded = true;
if (carryingCapacityWasExceeded == false) // if capacity isn't exceeded
for (int i = 0; i < arrayWithGeneratedNumbers.length; i++) // calculate strength
if (arrayWithGeneratedNumbers[i] != 0) // ignore 0, because I left units with 0 behind on the ground
currentStrength += strengths.get(i);
if (currentStrength > max) // is my current strength better than global maximum?
max = currentStrength; // replace my global maximum
bestArray = arrayWithGeneratedNumbers.clone(); // remember the new best layout of units
public static void main(String[] args)
HeroesOnTheBoat g = new HeroesOnTheBoat();
g.input("inputFile");
Example input:
2 60 40
30 400
20 500
50 100
40 100
30 50
60 75
40 20
and its result:
[1, 1, 0, 2, 0, 0, 0] this is the best layout of units
1000 this is the max strength we can achieve
java recursion time-limit-exceeded backtracking knapsack-problem
New contributor
$endgroup$
$begingroup$
Could you include the results of your example input?
$endgroup$
– dfhwze
7 hours ago
$begingroup$
@dfhwze The results are [1, 1, 0, 2, 0, 0, 0], which represents that units 0,1 and 4 will be on board. Units 0 and 1 on boat 0 and unit 4 on boat 1. The rest is left behind. 1000 this is the max strength we can achieve, because 400+500+100.
$endgroup$
– Jack
7 hours ago
add a comment |
$begingroup$
I solved the following problem using backtracking:
We are given a list of military units, their weight and their
(numerical) strength. We have a number of ships with a limited
carrying capacity. Determine how to load ships with military units, so
that carrying capacity for each ship is not exceed and so that we have
the maximum possible military strength on our ships.
However, my code is not fast enough, as there are many unnecessary calculations being done, that does not lead to a solution. How would I optimize my code? My idea is to use memoization, but how would I implement it?
I tried to comment my code and refactor my code as best as I can.
public class HeroesOntTheBoat {
private int[] arrayWithGeneratedNumbers;
private int numberOfShips;
private int max;
private int[] bestArray;
private ArrayList<Integer> strengths;
private ArrayList<Integer> weights;
private ArrayList<Integer> carryingCapacities;
public HeroesOntTheBoat()
carryingCapacities = new ArrayList<Integer>(); // create arraylist for the carrying capacities of ships
strengths = new ArrayList<Integer>(); //create arraylists for strengths and weights of units
weights = new ArrayList<Integer>(); //create arraylists for weights
max = 0; // global variable max for finding the best strength
private void generate(int fromIndex) // I generate all combinations between 0 and numberOfShips
if (fromIndex == arrayWithGeneratedNumbers.length) // 0 is representing that unit is being left behind
processGeneratedNumbers(); // 1,2,3,4..n are representing the number of ship that the unit is loaded on
return; // index of a number in array is representing a specific unit
for (int i = 0; i <= numberOfShips; i++)
arrayWithGeneratedNumbers[fromIndex] = i;
generate(fromIndex + 1);
public void input(String input)
Scanner sc = null;
try
sc = new Scanner(new File(input)); // load my input from a textfile
numberOfShips = sc.nextInt(); // load the number of ships
for (int i = 0; i < numberOfShips; i++) //add carrying capacities to arraylist
carryingCapacities.add(sc.nextInt());
bestArray = new int[weights.size()]; // array where we will remember the best combination of units
while (sc.hasNext())
weights.add(sc.nextInt());
strengths.add(sc.nextInt());
arrayWithGeneratedNumbers = new int[weights.size()]; // array where we will generate numbers
generate(0); // run the generation
System.out.println(Arrays.toString(bestArray) + " this is the best layout of units"); // after the generation is over
System.out.println(max + " this is the max strength we can achieve"); // print the results
catch (FileNotFoundException e)
System.err.println("FileNotFound");
finally
if (sc != null)
sc.close();
public void processGeneratedNumbers()
int currentStrength = 0; // process every generated result
boolean carryingCapacityWasExceeded = false;
int[] currentWeight = new int[numberOfShips + 1];
for (int i = 0; i < arrayWithGeneratedNumbers.length; i++) // calculate weights for every ship and ground
currentWeight[arrayWithGeneratedNumbers[i]] += weights.get(i);
for (int i = 0; i < currentWeight.length; i++) // is capacity exceeded?
if (i != 0 && currentWeight[i] > carryingCapacities.get(i - 1)) // ignore 0, because 0 represents ground(units I left behind)
carryingCapacityWasExceeded = true;
if (carryingCapacityWasExceeded == false) // if capacity isn't exceeded
for (int i = 0; i < arrayWithGeneratedNumbers.length; i++) // calculate strength
if (arrayWithGeneratedNumbers[i] != 0) // ignore 0, because I left units with 0 behind on the ground
currentStrength += strengths.get(i);
if (currentStrength > max) // is my current strength better than global maximum?
max = currentStrength; // replace my global maximum
bestArray = arrayWithGeneratedNumbers.clone(); // remember the new best layout of units
public static void main(String[] args)
HeroesOnTheBoat g = new HeroesOnTheBoat();
g.input("inputFile");
Example input:
2 60 40
30 400
20 500
50 100
40 100
30 50
60 75
40 20
and its result:
[1, 1, 0, 2, 0, 0, 0] this is the best layout of units
1000 this is the max strength we can achieve
java recursion time-limit-exceeded backtracking knapsack-problem
New contributor
$endgroup$
I solved the following problem using backtracking:
We are given a list of military units, their weight and their
(numerical) strength. We have a number of ships with a limited
carrying capacity. Determine how to load ships with military units, so
that carrying capacity for each ship is not exceed and so that we have
the maximum possible military strength on our ships.
However, my code is not fast enough, as there are many unnecessary calculations being done, that does not lead to a solution. How would I optimize my code? My idea is to use memoization, but how would I implement it?
I tried to comment my code and refactor my code as best as I can.
public class HeroesOntTheBoat {
private int[] arrayWithGeneratedNumbers;
private int numberOfShips;
private int max;
private int[] bestArray;
private ArrayList<Integer> strengths;
private ArrayList<Integer> weights;
private ArrayList<Integer> carryingCapacities;
public HeroesOntTheBoat()
carryingCapacities = new ArrayList<Integer>(); // create arraylist for the carrying capacities of ships
strengths = new ArrayList<Integer>(); //create arraylists for strengths and weights of units
weights = new ArrayList<Integer>(); //create arraylists for weights
max = 0; // global variable max for finding the best strength
private void generate(int fromIndex) // I generate all combinations between 0 and numberOfShips
if (fromIndex == arrayWithGeneratedNumbers.length) // 0 is representing that unit is being left behind
processGeneratedNumbers(); // 1,2,3,4..n are representing the number of ship that the unit is loaded on
return; // index of a number in array is representing a specific unit
for (int i = 0; i <= numberOfShips; i++)
arrayWithGeneratedNumbers[fromIndex] = i;
generate(fromIndex + 1);
public void input(String input)
Scanner sc = null;
try
sc = new Scanner(new File(input)); // load my input from a textfile
numberOfShips = sc.nextInt(); // load the number of ships
for (int i = 0; i < numberOfShips; i++) //add carrying capacities to arraylist
carryingCapacities.add(sc.nextInt());
bestArray = new int[weights.size()]; // array where we will remember the best combination of units
while (sc.hasNext())
weights.add(sc.nextInt());
strengths.add(sc.nextInt());
arrayWithGeneratedNumbers = new int[weights.size()]; // array where we will generate numbers
generate(0); // run the generation
System.out.println(Arrays.toString(bestArray) + " this is the best layout of units"); // after the generation is over
System.out.println(max + " this is the max strength we can achieve"); // print the results
catch (FileNotFoundException e)
System.err.println("FileNotFound");
finally
if (sc != null)
sc.close();
public void processGeneratedNumbers()
int currentStrength = 0; // process every generated result
boolean carryingCapacityWasExceeded = false;
int[] currentWeight = new int[numberOfShips + 1];
for (int i = 0; i < arrayWithGeneratedNumbers.length; i++) // calculate weights for every ship and ground
currentWeight[arrayWithGeneratedNumbers[i]] += weights.get(i);
for (int i = 0; i < currentWeight.length; i++) // is capacity exceeded?
if (i != 0 && currentWeight[i] > carryingCapacities.get(i - 1)) // ignore 0, because 0 represents ground(units I left behind)
carryingCapacityWasExceeded = true;
if (carryingCapacityWasExceeded == false) // if capacity isn't exceeded
for (int i = 0; i < arrayWithGeneratedNumbers.length; i++) // calculate strength
if (arrayWithGeneratedNumbers[i] != 0) // ignore 0, because I left units with 0 behind on the ground
currentStrength += strengths.get(i);
if (currentStrength > max) // is my current strength better than global maximum?
max = currentStrength; // replace my global maximum
bestArray = arrayWithGeneratedNumbers.clone(); // remember the new best layout of units
public static void main(String[] args)
HeroesOnTheBoat g = new HeroesOnTheBoat();
g.input("inputFile");
Example input:
2 60 40
30 400
20 500
50 100
40 100
30 50
60 75
40 20
and its result:
[1, 1, 0, 2, 0, 0, 0] this is the best layout of units
1000 this is the max strength we can achieve
java recursion time-limit-exceeded backtracking knapsack-problem
java recursion time-limit-exceeded backtracking knapsack-problem
New contributor
New contributor
edited 1 hour ago
200_success
135k21 gold badges173 silver badges443 bronze badges
135k21 gold badges173 silver badges443 bronze badges
New contributor
asked 8 hours ago
JackJack
133 bronze badges
133 bronze badges
New contributor
New contributor
$begingroup$
Could you include the results of your example input?
$endgroup$
– dfhwze
7 hours ago
$begingroup$
@dfhwze The results are [1, 1, 0, 2, 0, 0, 0], which represents that units 0,1 and 4 will be on board. Units 0 and 1 on boat 0 and unit 4 on boat 1. The rest is left behind. 1000 this is the max strength we can achieve, because 400+500+100.
$endgroup$
– Jack
7 hours ago
add a comment |
$begingroup$
Could you include the results of your example input?
$endgroup$
– dfhwze
7 hours ago
$begingroup$
@dfhwze The results are [1, 1, 0, 2, 0, 0, 0], which represents that units 0,1 and 4 will be on board. Units 0 and 1 on boat 0 and unit 4 on boat 1. The rest is left behind. 1000 this is the max strength we can achieve, because 400+500+100.
$endgroup$
– Jack
7 hours ago
$begingroup$
Could you include the results of your example input?
$endgroup$
– dfhwze
7 hours ago
$begingroup$
Could you include the results of your example input?
$endgroup$
– dfhwze
7 hours ago
$begingroup$
@dfhwze The results are [1, 1, 0, 2, 0, 0, 0], which represents that units 0,1 and 4 will be on board. Units 0 and 1 on boat 0 and unit 4 on boat 1. The rest is left behind. 1000 this is the max strength we can achieve, because 400+500+100.
$endgroup$
– Jack
7 hours ago
$begingroup$
@dfhwze The results are [1, 1, 0, 2, 0, 0, 0], which represents that units 0,1 and 4 will be on board. Units 0 and 1 on boat 0 and unit 4 on boat 1. The rest is left behind. 1000 this is the max strength we can achieve, because 400+500+100.
$endgroup$
– Jack
7 hours ago
add a comment |
1 Answer
1
active
oldest
votes
$begingroup$
The algorithm
This algorithm creates every combination of ships and tests them one by one, including combinations that could be seen to be useless by the first choice made. For example, if the first choice is to assign a unit of weight 60 to a ship with capacity 50, then it no longer matters what the rest of the content of arrayWithGeneratedNumbers
will be, there is no point recursively calling generate
when there is already such a problem.
The solution to that is checking as much as possible as early as possible. So in generate
, do not only check the solution when it is fully formed, check for capacity violations every time. That seems like more wasted work, but it's not a waste, it prevents a ton of recursion. If a capacity check fails early, thousands maybe millions of combinations will be skipped, by simply not generating them.
A similar related trick is computing the strength early, and returning back up the recursion tree once you see that the current branch cannot result in a better solution than some solution that you already have. So this only works if there is some non-trivial solution already, and it is useful to do a simple greedy pass first to initialize with, so more of the recursion is pruned right from the start.
With pruning, the order in which choices are made matters: pruning near the root of the tree is orders of magnitude better than pruning near the leafs. A general rule of thumb is to pick the most-constrained item first, and try the least-constraining choice for it first. So in this domain, pick the heaviest unit, and put it on the biggest ship. However, we can also make use of the strengths and go for units with a high strength-per-weight ratio first, relying on the idea of filling the ships with good units first and then trying to "fill the gaps" with worse units. There are different strategies here, probably almost anything is better than not using a strategy.
Naming
There are several extremely generic names in this code, bordering on meaninglessness. generate
, generate what? processGeneratedNumbers
, what is process? What are "generated numbers"? arrayWithGeneratedNumbers
, variable names shouldn't repeat their type and again what are "generated numbers". This is not an abstract domain where we don't know what is being generated or what the numbers mean, the data here has a specific meaning, and the methods do specific things. So you could use names such as:
unitAssignment
, in the sense of assigning units to ships. OrshipAssignment
, in the same sense.isAssignmentValid
,checkCapacities
, something like that. That's for the version that does not also update the best-solution-so-far, just pure checking for the purpose of pruning.
Also I wouldn't put the unrelated input
between two related methods.
Boolean flag logic
Always a contentious point, but I would say, as a rough approximation, the fewer boolean flags the better. Return when the first checks fails, no messy business with flags.
$endgroup$
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Jack is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f225939%2floading-military-units-into-ships-optimally-using-backtracking%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
The algorithm
This algorithm creates every combination of ships and tests them one by one, including combinations that could be seen to be useless by the first choice made. For example, if the first choice is to assign a unit of weight 60 to a ship with capacity 50, then it no longer matters what the rest of the content of arrayWithGeneratedNumbers
will be, there is no point recursively calling generate
when there is already such a problem.
The solution to that is checking as much as possible as early as possible. So in generate
, do not only check the solution when it is fully formed, check for capacity violations every time. That seems like more wasted work, but it's not a waste, it prevents a ton of recursion. If a capacity check fails early, thousands maybe millions of combinations will be skipped, by simply not generating them.
A similar related trick is computing the strength early, and returning back up the recursion tree once you see that the current branch cannot result in a better solution than some solution that you already have. So this only works if there is some non-trivial solution already, and it is useful to do a simple greedy pass first to initialize with, so more of the recursion is pruned right from the start.
With pruning, the order in which choices are made matters: pruning near the root of the tree is orders of magnitude better than pruning near the leafs. A general rule of thumb is to pick the most-constrained item first, and try the least-constraining choice for it first. So in this domain, pick the heaviest unit, and put it on the biggest ship. However, we can also make use of the strengths and go for units with a high strength-per-weight ratio first, relying on the idea of filling the ships with good units first and then trying to "fill the gaps" with worse units. There are different strategies here, probably almost anything is better than not using a strategy.
Naming
There are several extremely generic names in this code, bordering on meaninglessness. generate
, generate what? processGeneratedNumbers
, what is process? What are "generated numbers"? arrayWithGeneratedNumbers
, variable names shouldn't repeat their type and again what are "generated numbers". This is not an abstract domain where we don't know what is being generated or what the numbers mean, the data here has a specific meaning, and the methods do specific things. So you could use names such as:
unitAssignment
, in the sense of assigning units to ships. OrshipAssignment
, in the same sense.isAssignmentValid
,checkCapacities
, something like that. That's for the version that does not also update the best-solution-so-far, just pure checking for the purpose of pruning.
Also I wouldn't put the unrelated input
between two related methods.
Boolean flag logic
Always a contentious point, but I would say, as a rough approximation, the fewer boolean flags the better. Return when the first checks fails, no messy business with flags.
$endgroup$
add a comment |
$begingroup$
The algorithm
This algorithm creates every combination of ships and tests them one by one, including combinations that could be seen to be useless by the first choice made. For example, if the first choice is to assign a unit of weight 60 to a ship with capacity 50, then it no longer matters what the rest of the content of arrayWithGeneratedNumbers
will be, there is no point recursively calling generate
when there is already such a problem.
The solution to that is checking as much as possible as early as possible. So in generate
, do not only check the solution when it is fully formed, check for capacity violations every time. That seems like more wasted work, but it's not a waste, it prevents a ton of recursion. If a capacity check fails early, thousands maybe millions of combinations will be skipped, by simply not generating them.
A similar related trick is computing the strength early, and returning back up the recursion tree once you see that the current branch cannot result in a better solution than some solution that you already have. So this only works if there is some non-trivial solution already, and it is useful to do a simple greedy pass first to initialize with, so more of the recursion is pruned right from the start.
With pruning, the order in which choices are made matters: pruning near the root of the tree is orders of magnitude better than pruning near the leafs. A general rule of thumb is to pick the most-constrained item first, and try the least-constraining choice for it first. So in this domain, pick the heaviest unit, and put it on the biggest ship. However, we can also make use of the strengths and go for units with a high strength-per-weight ratio first, relying on the idea of filling the ships with good units first and then trying to "fill the gaps" with worse units. There are different strategies here, probably almost anything is better than not using a strategy.
Naming
There are several extremely generic names in this code, bordering on meaninglessness. generate
, generate what? processGeneratedNumbers
, what is process? What are "generated numbers"? arrayWithGeneratedNumbers
, variable names shouldn't repeat their type and again what are "generated numbers". This is not an abstract domain where we don't know what is being generated or what the numbers mean, the data here has a specific meaning, and the methods do specific things. So you could use names such as:
unitAssignment
, in the sense of assigning units to ships. OrshipAssignment
, in the same sense.isAssignmentValid
,checkCapacities
, something like that. That's for the version that does not also update the best-solution-so-far, just pure checking for the purpose of pruning.
Also I wouldn't put the unrelated input
between two related methods.
Boolean flag logic
Always a contentious point, but I would say, as a rough approximation, the fewer boolean flags the better. Return when the first checks fails, no messy business with flags.
$endgroup$
add a comment |
$begingroup$
The algorithm
This algorithm creates every combination of ships and tests them one by one, including combinations that could be seen to be useless by the first choice made. For example, if the first choice is to assign a unit of weight 60 to a ship with capacity 50, then it no longer matters what the rest of the content of arrayWithGeneratedNumbers
will be, there is no point recursively calling generate
when there is already such a problem.
The solution to that is checking as much as possible as early as possible. So in generate
, do not only check the solution when it is fully formed, check for capacity violations every time. That seems like more wasted work, but it's not a waste, it prevents a ton of recursion. If a capacity check fails early, thousands maybe millions of combinations will be skipped, by simply not generating them.
A similar related trick is computing the strength early, and returning back up the recursion tree once you see that the current branch cannot result in a better solution than some solution that you already have. So this only works if there is some non-trivial solution already, and it is useful to do a simple greedy pass first to initialize with, so more of the recursion is pruned right from the start.
With pruning, the order in which choices are made matters: pruning near the root of the tree is orders of magnitude better than pruning near the leafs. A general rule of thumb is to pick the most-constrained item first, and try the least-constraining choice for it first. So in this domain, pick the heaviest unit, and put it on the biggest ship. However, we can also make use of the strengths and go for units with a high strength-per-weight ratio first, relying on the idea of filling the ships with good units first and then trying to "fill the gaps" with worse units. There are different strategies here, probably almost anything is better than not using a strategy.
Naming
There are several extremely generic names in this code, bordering on meaninglessness. generate
, generate what? processGeneratedNumbers
, what is process? What are "generated numbers"? arrayWithGeneratedNumbers
, variable names shouldn't repeat their type and again what are "generated numbers". This is not an abstract domain where we don't know what is being generated or what the numbers mean, the data here has a specific meaning, and the methods do specific things. So you could use names such as:
unitAssignment
, in the sense of assigning units to ships. OrshipAssignment
, in the same sense.isAssignmentValid
,checkCapacities
, something like that. That's for the version that does not also update the best-solution-so-far, just pure checking for the purpose of pruning.
Also I wouldn't put the unrelated input
between two related methods.
Boolean flag logic
Always a contentious point, but I would say, as a rough approximation, the fewer boolean flags the better. Return when the first checks fails, no messy business with flags.
$endgroup$
The algorithm
This algorithm creates every combination of ships and tests them one by one, including combinations that could be seen to be useless by the first choice made. For example, if the first choice is to assign a unit of weight 60 to a ship with capacity 50, then it no longer matters what the rest of the content of arrayWithGeneratedNumbers
will be, there is no point recursively calling generate
when there is already such a problem.
The solution to that is checking as much as possible as early as possible. So in generate
, do not only check the solution when it is fully formed, check for capacity violations every time. That seems like more wasted work, but it's not a waste, it prevents a ton of recursion. If a capacity check fails early, thousands maybe millions of combinations will be skipped, by simply not generating them.
A similar related trick is computing the strength early, and returning back up the recursion tree once you see that the current branch cannot result in a better solution than some solution that you already have. So this only works if there is some non-trivial solution already, and it is useful to do a simple greedy pass first to initialize with, so more of the recursion is pruned right from the start.
With pruning, the order in which choices are made matters: pruning near the root of the tree is orders of magnitude better than pruning near the leafs. A general rule of thumb is to pick the most-constrained item first, and try the least-constraining choice for it first. So in this domain, pick the heaviest unit, and put it on the biggest ship. However, we can also make use of the strengths and go for units with a high strength-per-weight ratio first, relying on the idea of filling the ships with good units first and then trying to "fill the gaps" with worse units. There are different strategies here, probably almost anything is better than not using a strategy.
Naming
There are several extremely generic names in this code, bordering on meaninglessness. generate
, generate what? processGeneratedNumbers
, what is process? What are "generated numbers"? arrayWithGeneratedNumbers
, variable names shouldn't repeat their type and again what are "generated numbers". This is not an abstract domain where we don't know what is being generated or what the numbers mean, the data here has a specific meaning, and the methods do specific things. So you could use names such as:
unitAssignment
, in the sense of assigning units to ships. OrshipAssignment
, in the same sense.isAssignmentValid
,checkCapacities
, something like that. That's for the version that does not also update the best-solution-so-far, just pure checking for the purpose of pruning.
Also I wouldn't put the unrelated input
between two related methods.
Boolean flag logic
Always a contentious point, but I would say, as a rough approximation, the fewer boolean flags the better. Return when the first checks fails, no messy business with flags.
answered 7 hours ago
haroldharold
1,9666 silver badges10 bronze badges
1,9666 silver badges10 bronze badges
add a comment |
add a comment |
Jack is a new contributor. Be nice, and check out our Code of Conduct.
Jack is a new contributor. Be nice, and check out our Code of Conduct.
Jack is a new contributor. Be nice, and check out our Code of Conduct.
Jack is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f225939%2floading-military-units-into-ships-optimally-using-backtracking%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
$begingroup$
Could you include the results of your example input?
$endgroup$
– dfhwze
7 hours ago
$begingroup$
@dfhwze The results are [1, 1, 0, 2, 0, 0, 0], which represents that units 0,1 and 4 will be on board. Units 0 and 1 on boat 0 and unit 4 on boat 1. The rest is left behind. 1000 this is the max strength we can achieve, because 400+500+100.
$endgroup$
– Jack
7 hours ago