Problem Description :
The travelling salesman problem (also called the travelling salesperson problem or TSP) asks the following question: "Given a list of cities and the distances between each pair of cities, what is the shortest possible route that visits each city and returns to the origin city?"
My solution :
I used The Backtracking Method, and i used that Google Guava library to construct graphs the only problem is i my code don't return the initial city , by example if we have A , B , C , D cities and the shortest trajectory is A ,B , D, C we have to return to the initial city Like A ,B , D, C, A Here is the the code (or you can check the following github link to understand the problem better https://charlesreid1.github.io/solving-the-traveling-salesperson-problem-with-java-and-guava.html :
package com.Faissal;
import com.google.common.graph.ImmutableNetwork;
import com.google.common.graph.MutableNetwork;
import com.google.common.graph.NetworkBuilder;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
class TSP {
// The actual graph of cities
ImmutableNetwork<Node, Edge> graph;
int graphSize;
// Storage variables used when searching for a solution
String[] route; // store the route
double this_distance; // store the total distance
double min_distance; // store the shortest path found so far
/**
* Defaut constructor generates the graph and initializes storage variables
*/
public TSP() {
// Build the graph
this.graph = buildGraph();
this.graphSize = this.graph.nodes().size();
// Initialize route variable, shared across recursive method instances
this.route = new String[this.graphSize];
// Initialize distance variable, shared across recursive method instances
this.this_distance = 0.0;
this.min_distance = -1.0; // negative min means uninitialized
}
/**
* This method actually constructs the graph.
*/
public ImmutableNetwork<Node, Edge> buildGraph() {
// MutableNetwork is an interface requiring a type for nodes and a type for edges
MutableNetwork<Node, Edge> roads = NetworkBuilder.undirected().build();
// Construct Nodes for cities,
// and add them to a map
String[] cities = {"Wuhan", "shanghai", "Beijing", "Tianjin", "dalian"};
Map<String, Node> all_nodes = new TreeMap<String, Node>();
for (int i = 0; i < cities.length; i++) {
// Add nodes to map
Node node = new Node(cities[i]);
all_nodes.put(cities[i], node);
// Add nodes to network
roads.addNode(node);
}
// Construct Edges for roads,
// and add them to a map
String[] distances = {"Wuhan:shanghai:839", "Wuhan:Beijing:1153", "Wuhan:Tianjin:1162", "Wuhan:dalian:1423", "shanghai:Beijing:1214", "shanghai:Tianjin:20", "Beijing:Tianjin:4", "shanghai:dalian:1076", "Tianjin:dalian:802"};
Map<String, Edge> all_edges = new TreeMap<String, Edge>();
for (int j = 0; j < distances.length; j++) {
// Parse out (city1):(city2):(distance)
String[] splitresult = distances[j].split(":");
String left = splitresult[0];
String right = splitresult[1];
String label = left + ":" + right;
int value = Integer.parseInt(splitresult[2]);
// Add edges to map
Edge edge = new Edge(left, right, value);
all_edges.put(label, edge);
// Add edges to network
roads.addEdge(all_nodes.get(edge.left), all_nodes.get(edge.right), edge);
}
// Freeze the network
ImmutableNetwork<Node, Edge> frozen_roads = ImmutableNetwork.copyOf(roads);
return frozen_roads;
}
/**
/** Public solve method will call the recursive backtracking method to search for solutions on the graph */
public void solve() {
/** To solve the traveling salesman problem:
* Set up the graph, choose a starting node, then call the recursive backtracking method and pass it the starting node.
*/
// We need to pass a starting node to recursive backtracking method
Node startNode = null;
// Grab a node, any node...
for( Node n : graph.nodes() ) {
startNode = n;
break;
}
// Visit the first node
startNode.visit();
// Add first node to the route
this.route[0] = startNode.label;
// Pass the number of choices made
int nchoices = 1;
// Recursive backtracking
explore(startNode, nchoices);
}
/** Recursive backtracking method: explore possible solutions starting at this node, having made nchoices */
/**
* Recursive backtracking method: explore possible solutions starting at this node, having made nchoices
* #return
*/
public void explore(Node node, int nchoices) {
/**
* Solution strategy: recursive backtracking.
*/
if (nchoices == graphSize) {
//
// BASE CASE
//
if (this.this_distance < this.min_distance || this.min_distance < 0) {
// if this_distance < min_distance, this is our new minimum distance
// if min_distance < 0, this is our first minimium distance
this.min_distance = this.this_distance;
printSolution();
} else {
printFailure();
}
} else {
//
// RECURSIVE CASE
//
Set<Node> neighbors = graph.adjacentNodes(node);
for (Node neighbor : neighbors) {
if (neighbor.visited == false) {
int distance_btwn = 0;
for (Edge edge : graph.edgesConnecting(node, neighbor)) {
distance_btwn = edge.value;
}
// Make a choice
this.route[nchoices] = neighbor.label;
neighbor.visit();
this.this_distance += distance_btwn;
// Explore the consequences
explore(neighbor, nchoices + 1);
// Unmake the choice
this.route[nchoices] = null;
neighbor.unvisit();
this.this_distance -= distance_btwn;
}
// Move on to the next choice (continue loop)
}
} // End base/recursive case
}
public void printSolution() {
System.out.print("***********\tNEW SOLUTION\t");
System.out.println("Route: " + Arrays.toString(this.route)
+ "\tDistance: " + this.min_distance);
}
/**
* Do nothing with failed path
*/
public void printFailure() {
//
}
}
The Node Class is
```
class Node {
public String label;
public boolean visited; // Helps us to keep track of where we've been on the graph
public Node(String name){
this.label = name;
this.visited = false;
}
public void visit(){
this.visited = true;
}
public void unvisit() {
this.visited = false;
}
}
The Edge Class :
```
class Edge {
public int value;
public String left, right; // For convenience in construction process. Not necessary.
public Edge(String left, String right, int value) {
this.left = left;
this.right = right;
this.value = value;
}
}
The main class
```
public class Main {
public static void main(String[] args) {
TSP t = new TSP();
t.solve();
}
}
I will be very Thankful if someone helped me with this issue
You're almost there, you just have to move back to the origin.
For that you have to have a reference of the origin in TSP.explore. You could store it somewhere in this.startNode or make route an array of Nodes: Node[] route
Then you can check in TSP.explore, if the last node has the origin as its neighbor, add that distance to the total distance and go on like usual.
It basically comes down to this:
// Store Nodes instead of Strings. Edit this everywhere you use it.
Node[] route;
// ...
if (nchoices == graphSize) {
//
// BASE CASE: VISITED EACH NODE
//
Set<Node> neighbors = graph.adjacentNodes(node);
// It's only a solution, if there is a edge to the first node.
if(neighbors.contains(this.route[0])) {
// Same computation as in the else-block.
int distance_btwn = this.getDistanceBetween(node, neighbor);
// Add the distance to the start node.
int total_distance = this.this_distance + distance_btwn;
if (total_distance < this.min_distance || this.min_distance < 0) {
// if this_distance < min_distance, this is our new minimum distance
// if min_distance < 0, this is our first minimium distance
this.min_distance = total_distance;
// You have to tell printSolution to about total_distance somehow.
printSolution(total_distance);
return;
}
}
printFailure();
}
I have to preprocess 4 lists of medical data before we can import it into the software.
I have given 4 lists, each ordered already, that look like the following:
File 1) chapter
A00-B99;
C00-D48;
D50-D89;
C00-C99;
E00-E90;
...
Z00-Z99;
File 2) subchapter
A00-A09;
A15-A19;
A92-A99;
B95-B98;
B99-B99;
C00-C48;
...
Z80-Z99;
File 3) Groups
A00.-
A01.-
A02.-
...
C01.-
....
Z99.-
File 4) diagnoses
A00.0;
A00.1;
A00.7;
A00.8;
A01.7;
A02.8;
..
Z00.3;
Z00.4;
;
At the End it shoud be ordered as the list below.
Each line will be a line within a csv-file.
A00-B99; (Chapter)
A00-A09; (Subchapter)
A00.- (corresponding group)
A00.0 (corresponding diagnoses)
A00.1
A00.7
A00.8
A01.- (corresponding group)
A01.7 (corresponding diagnoses)
A02.- (corresponding group)
A02.8 (corresponding diagnoses)
...
B15-B99(Subchapter)
...
C00-C99 (Chapter)
C00-D48 (Subchapter)
C01.- (corresponding group)
C01.2 (corresponding diagnoses)
I've tried it so far by using some linked hasmaps but don't get the correct result.
while (entries_kapitel.hasNext()) {
Entry thisEntry_kapitel = (Entry) entries_kapitel.next();
String key_kapitel = (String) thisEntry_kapitel.getKey();
String text_kapitel = (String) thisEntry_kapitel.getValue();
// A00-B99 -> A und B
String kapitel_char1 = key_kapitel.split("-")[0].substring(0, 1);
String kapitel_char2 = key_kapitel.split("-")[1].substring(0, 1);
// A00-B99 -> 99
int kapitel_int2 = Integer.parseInt(key_kapitel.split("-")[1].substring(1, 3));
// subchapters
while (entries_gruppen.hasNext()) {
Entry thisEntry_gruppen = (Entry) entries_gruppen.next();
String key_gruppen = (String) thisEntry_gruppen.getKey();
String text_gruppen = (String) thisEntry_gruppen.getValue();
// Gruppe splitten T90-T89
String gruppe_char1 = key_gruppen.split("-")[0].substring(0, 1);
String gruppe_char2 = key_gruppen.split("-")[1].substring(0, 1);
int gruppe_int2 = Integer.parseInt(key_gruppen.split("-")[1].substring(1, 3));
if (gruppe_char1.equals(gruppe_char2) == false){
System.err.println("Subchapters start with the same capital!");
System.exit(1);
}
while (entries_gruppierung.hasNext()) {
Entry thisEntry_gruppierung = (Entry) entries_gruppierung.next();
String key_gruppierung = (String) thisEntry_gruppierung.getKey();
String text_gruppierung = (String) thisEntry_gruppierung.getValue();
String gruppierung_char1 = key_gruppierung.substring(0, 1);
int gruppierung_int1 = Integer.parseInt(key_gruppierung.substring(1, 3));
(gruppierung_char1.equals(gruppe_char1) && gruppierung_int1 <= gruppe_int2) {
System.out.println("Chapter: " + key_kapitel + " subchapter: " + key_gruppen + " group" + key_gruppierung);
while (diagnoses.hasNext()) {
....
The result does not look like it should (there are missing entries and they are not all ordered correctly)
What is the best way to solve this task?
I was not able to get a working tree, which probably is the best way to go, right?
If I understod well you're needs. I would use a SORT / MERGE join approach. Consider 4 lists containing the entries, properly sorted. Then you can merge the lists by scanning them alternately. I haven't tested the code but you'll get the general idea :
public class EntryComparator implements Comparator<Entry>
{
public boolean isSubsection(Entry e1, Entry e2)
{
// should return true if e2 subsection of e1
}
public int compare(Entry e1, Entry e2)
{
// see the Comparator interface documentation
}
}
List<Entry> chapters = new ArrayList<>();
List<Entry> subchapters = new ArrayList<>();
List<Entry> groups = new ArrayList<>();
List<Entry> diagnoses = new ArrayList<>();
List<Entry> result = new ArrayList<>(); // will hold the final result
// populate the lists, maybe sort them using Collections.sort and the Comparator above
int i1 = 0;
int i2 = 0;
int i3 = 0;
int i4 = 0;
EntryComparator c = new EntryComparator();
while( i1 < chapters.size() )
{
result.add(chapters.get(i1));
while( i2 < subchapters.size() &&
c.isSubsection(chapters.get(i1), subchapters.get(i2)) )
{
result.add(subchapters.get(i2));
while( i3 < groups.size() &&
c.isSubsection(subchapters.get(i2), groups.get(i3)) )
{
result.add(groups.get(i3));
while( i4 < subchapters.size() &&
c.isSubsection(groups.get(i3), diagnoses.get(i4)) )
{
result.add(diagnoses.get(i4));
i4++;
}
i3++;
}
i2++;
}
i1++;
}
EDIT : the advice given by 911DidBush is a good one, you may apply the same pattern with specialized classes.
thanks for your replies. As recommended, I will implement each list as a Class. This seems a really good idea. The Class Chapter will look like this. The other classes are having the same structure as well.
public class Chapter {
private String key_chapter;
private String text;
private ArrayList<Subchapter> subchapters = new ArrayList<>();
public Chapter(String chapter, String text) {
this.key_chapter = chapter;
this.text = text;
subchapters = new ArrayList<Subchapter>();
}
public String getChapter() {
return key_chapter;
}
public String getText() {
return text;
}
public void addSubchapter(String subchapter, String text) {
subchapters.add(new Subchapter(subchapter, text));
}
public Subchapter getKeyAtIndex(int index) {
return subchapters.get(index);
}
// get the entire ArrayList:
public ArrayList getListOfSubchapters() {
return subchapters;
}
}
I have been working on something the past few days that seems to be working as intended, however I am looking for ways to improve it. I have a set of n items, and I need to put together groups of these items that MUST meet ALL of the following requirements:
2 items from Category A
2 items from Category B
2 items from Category C
2 Items from Category D
1 item from Category E
I am currently using the following recursive method to put my groups together and the isValid() method is being used to determine if the group meets the criteria.
void getGroups(String[] arr, int len, int startPosition, String[] result) {
if(len == 0) {
Group group = new Group(Arrays.asList(result));
if(group.isValid()) {
validGroups.add(group);
group.printGroup();
}
return;
}
for(int i = startPosition; i <= arr.length - len; i++) {
result[result.length - len] = arr[i];
getGroups(arr, len - 1, i + 1, result);
}
}
I am able to see valid results get printed as the program runs, however the original size of items that I am working with can be well over 100 items. This means there is a very large number of total possible groups that will be iterated through and a lot of times the program never actually completes.
I know that there are currently a bunch of wasted iterations, for example if at some point I detect a group is invalid because it has 3 items from Category A, I should be able to move on. I am not sure if my current method with a few tweaks is the best way to go about this, or if I should separate the items into their respective groups first, and then from their put only valid combinations together. Any help would be appreciated. Thanks.
EDIT: I tried to make the method a bit more simpler than my actual method. My actual method takes in an array of Objects that I've created that contain their value along with their category. I guess for the example we can assume that each category is represented by a list of Strings that it contains. The method can be called like:
String[] items = {"test1", "test2", "test3", "test4", "test5", "test6", "test7",
"test8", "test9", "test10", "test11", "test12", "test13",
"test14", "test15", "test16", "test17", "test18"};
getGroups(items, 9, 0, new String[9]);
EDIT2:
List<String> catA = new ArrayList<String>();
catA.add("test1");
catA.add("test2");
catA.add("test3");
catA.add("test4");
List<String> catB = new ArrayList<String>();
catB.add("test5");
catB.add("test6");
catB.add("test7");
catB.add("test8");
List<String> catC = new ArrayList<String>();
catC.add("test9");
catC.add("test10");
catC.add("test11");
catC.add("test12");
List<String> catS = new ArrayList<String>();
catD.add("test13");
catD.add("test14");
catD.add("test15");
catD.add("test16");
List<String> catE = new ArrayList<String>();
catE.add("test17");
catE.add("test18");
Output:
{"test1", "test2", "test5", "test6", "test9", "test10", "test13", "test14", "test17"}
{"test1", "test2", "test5", "test6", "test9", "test10", "test13", "test14", "test18"}
{"test1", "test2", "test5", "test6", "test9", "test10", "test13", "test16", "test17"}
{"test1", "test2", "test5", "test6", "test9", "test10", "test13", "test15", "test17"}
{"test1", "test2", "test5", "test6", "test9", "test10", "test14", "test15", "test17"}
etc...
This seems to work.
I use a BitPattern iterator I wrote a while ago that walks all n-bit numbers containing just k set bits and uses that to select from your categories.
Note that much of this code is building the test data to reflect your requirements.
I hold a List of Iterables which are the BitPatterns. A list of Iterators which are the currently in-use Iterators from the BitPatterns (they must be renewed every time they complete) and a List of BigIntgers that are the current values to explode into selections from the data.
public class Test {
enum Category {
A(2), B(2), C(2), D(2), E(1);
public final int required;
Category(int required) {
this.required = required;
}
}
private static final Category[] categories = Category.values();
static class Categorised {
final String name;
final Category category;
Categorised(String name, Category category) {
this.name = name;
this.category = category;
}
#Override
public String toString() {
return category.name() + ":" + name;
}
}
static final List<Categorised> data = new ArrayList<>();
static {
data.add(new Categorised("A-1", Category.A));
data.add(new Categorised("A-2", Category.A));
data.add(new Categorised("A-3", Category.A));
data.add(new Categorised("B-1", Category.B));
data.add(new Categorised("B-2", Category.B));
data.add(new Categorised("B-3", Category.B));
data.add(new Categorised("C-1", Category.C));
data.add(new Categorised("C-2", Category.C));
data.add(new Categorised("C-3", Category.C));
data.add(new Categorised("D-1", Category.D));
data.add(new Categorised("D-2", Category.D));
data.add(new Categorised("D-3", Category.D));
data.add(new Categorised("E-1", Category.E));
data.add(new Categorised("E-2", Category.E));
data.add(new Categorised("E-3", Category.E));
}
// Categorise the data.
private Map<Category, List<Categorised>> categorise(List<Categorised> data) {
Map<Category, List<Categorised>> categorised = new EnumMap<>(Category.class);
for (Categorised d : data) {
List<Categorised> existing = categorised.get(d.category);
if (existing == null) {
existing = new ArrayList<>();
categorised.put(d.category, existing);
}
existing.add(d);
}
return categorised;
}
public void test() {
// Categorise the data.
Map<Category, List<Categorised>> categorised = categorise(data);
// Build my lists.
// A source of Iteratprs.
List<BitPattern> is = new ArrayList<>(categories.length);
// The Iterators.
List<Iterator<BigInteger>> its = new ArrayList<>(categories.length);
// The current it patterns to use to select.
List<BigInteger> next = new ArrayList<>(categories.length);
for (Category c : categories) {
int k = c.required;
List<Categorised> from = categorised.get(c);
// ToDo - Make sure there are enough.
int n = from.size();
// Make my iterable.
BitPattern p = new BitPattern(k, n);
is.add(p);
// Gather an Iterator.
Iterator<BigInteger> it = p.iterator();
// Store it.
its.add(it);
// Prime it.
next.add(it.next());
}
// Walk the lists.
boolean stepped;
do {
// Interpret the current numbers.
List<Categorised> candidates = new ArrayList<>();
for ( int c = 0; c < categories.length; c++ ) {
BigInteger b = next.get(c);
List<Categorised> category = categorised.get(categories[c]);
// Step through the bits in the number.
BitSet bs = BitSet.valueOf(b.toByteArray());
for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
// Pull those entries from the categorised list.
candidates.add(category.get(i));
}
}
// Print it for now.
System.out.println(candidates);
// Step again.
stepped = step(is, its, next);
} while (stepped);
}
// Take one step.
private boolean step(List<BitPattern> is, List<Iterator<BigInteger>> its, List<BigInteger> next) {
boolean stepped = false;
// Step each one until we make one successful step.
for (int i = 0; i < is.size() && !stepped; i++) {
Iterator<BigInteger> it = its.get(i);
if (it.hasNext()) {
// Done here!
stepped = true;
} else {
// Exhausted - Reset it.
its.set(i, it = is.get(i).iterator());
}
// Pull that one.
next.set(i, it.next());
}
return stepped;
}
public static void main(String args[]) {
new Test().test();
}
}
This is the BitPattern iterator.
/**
* Iterates all bit patterns containing the specified number of bits.
*
* See "Compute the lexicographically next bit permutation"
* http://graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation
*
* #author OldCurmudgeon
*/
public class BitPattern implements Iterable<BigInteger> {
// Useful stuff.
private static final BigInteger ONE = BigInteger.ONE;
private static final BigInteger TWO = ONE.add(ONE);
// How many bits to work with.
private final int bits;
// Value to stop at. 2^max_bits.
private final BigInteger stop;
// Should we invert the output.
private final boolean not;
// All patterns of that many bits up to the specified number of bits - invberting if required.
public BitPattern(int bits, int max, boolean not) {
this.bits = bits;
this.stop = TWO.pow(max);
this.not = not;
}
// All patterns of that many bits up to the specified number of bits.
public BitPattern(int bits, int max) {
this(bits, max, false);
}
#Override
public Iterator<BigInteger> iterator() {
return new BitPatternIterator();
}
/*
* From the link:
*
* Suppose we have a pattern of N bits set to 1 in an integer and
* we want the next permutation of N 1 bits in a lexicographical sense.
*
* For example, if N is 3 and the bit pattern is 00010011, the next patterns would be
* 00010101, 00010110, 00011001,
* 00011010, 00011100, 00100011,
* and so forth.
*
* The following is a fast way to compute the next permutation.
*/
private class BitPatternIterator implements Iterator<BigInteger> {
// Next to deliver - initially 2^n - 1
BigInteger next = TWO.pow(bits).subtract(ONE);
// The last one we delivered.
BigInteger last;
#Override
public boolean hasNext() {
if (next == null) {
// Next one!
// t gets v's least significant 0 bits set to 1
// unsigned int t = v | (v - 1);
BigInteger t = last.or(last.subtract(BigInteger.ONE));
// Silly optimisation.
BigInteger notT = t.not();
// Next set to 1 the most significant bit to change,
// set to 0 the least significant ones, and add the necessary 1 bits.
// w = (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctz(v) + 1));
// The __builtin_ctz(v) GNU C compiler intrinsic for x86 CPUs returns the number of trailing zeros.
next = t.add(ONE).or(notT.and(notT.negate()).subtract(ONE).shiftRight(last.getLowestSetBit() + 1));
if (next.compareTo(stop) >= 0) {
// Dont go there.
next = null;
}
}
return next != null;
}
#Override
public BigInteger next() {
last = hasNext() ? next : null;
next = null;
return not ? last.not(): last;
}
#Override
public void remove() {
throw new UnsupportedOperationException("Not supported.");
}
#Override
public String toString () {
return next != null ? next.toString(2) : last != null ? last.toString(2): "";
}
}
}
I will not write code but will list a possible approach. I say possible because it will be running and storing all data in memory and is not the best in regard to algorithms. yet, it is an approach where you don't need to eliminate invalid options. I will use an example in order to make things more clear.
suppose you have categories A,B,C. Where K=2 for A,B and K=1 for C.
you also have the input items A1,B1,B2,A2,C1,A3
1- go over the items and divide them according to their category. so you prepare an array/list for each category that has all the items that belong to it.
so now you have arrays:
Category A = [A1,A2,A3] , Category B = [B1,B2] and Category C=[C1]
2- now after preparing the lists, prepare the various legal groups that you can have for picking K items from N items found in that list . here is a link that might help in doing that efficiently: How to iteratively generate k elements subsets from a set of size n in java?
now you have:
first group belonging to category A:
[A1,A2] , [A1,A3], [A2,A3] (3 elements)
second group belonging to category B:
[B1,B2] (1 element)
third group belonging to category C:
[C1] (1 element)
3- now, if you treat each such group as an item, the question transforms to how many different ways are there for picking exactly one element from each group. and that is supposed to be easier to program recursively and will not require eliminating options. and if the number of categories is constant, it will be nested loops over the sets of groups in second point above.
EDIT
the approach works well in eliminating the need to validate bad combinations.
yet, there will still be a problem in regard of time. Here is the code that I made to demonstrate. it makes a list of 100 items. then it does the steps mentioned.
Note that I commented out the code that prints the groups.
The calculation is very fast up to that point. I have added code that prints how many legal choices can be made from each group.
package tester;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
/**
*
* #author
*/
public class Tester {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
//generate 100 random items belonging to categories
Random rand=new Random();
List<Item> items=new ArrayList<>();
int a=1,b=1,c=1,d=1,e=1;
for (int i=0;i<100;i++){
int randomNumber=rand.nextInt(5)+1;
CATEGORY_TYPE categoryType=null;
int num=0;
switch (randomNumber) {
case 1:
categoryType=CATEGORY_TYPE.A;
num=a++;
break;
case 2:
categoryType=CATEGORY_TYPE.B;
num=b++;
break;
case 3:
categoryType=CATEGORY_TYPE.C;
num=c++;
break;
case 4:
categoryType=CATEGORY_TYPE.D;
num=d++;
break;
case 5:
categoryType=CATEGORY_TYPE.E;
num=e++;
break;
}
String dummyData="Item "+categoryType.toString()+num;
Item item=new Item(dummyData,categoryType);
items.add(item);
}
//arrange the items in lists by category
List<Item> categoryAItemsList=new ArrayList<>();
List<Item> categoryBItemsList=new ArrayList<>();
List<Item> categoryCItemsList=new ArrayList<>();
List<Item> categoryDItemsList=new ArrayList<>();
List<Item> categoryEItemsList=new ArrayList<>();
for (Item item:items){
if (item.getCategoryType()==CATEGORY_TYPE.A)
categoryAItemsList.add(item);
else if (item.getCategoryType()==CATEGORY_TYPE.B)
categoryBItemsList.add(item);
else if (item.getCategoryType()==CATEGORY_TYPE.C)
categoryCItemsList.add(item);
else if (item.getCategoryType()==CATEGORY_TYPE.D)
categoryDItemsList.add(item);
else if (item.getCategoryType()==CATEGORY_TYPE.E)
categoryEItemsList.add(item);
}
//now we want to construct lists of possible groups of choosing from each category
List<Item[]> subsetStoringListA=new ArrayList<>();
List<Item[]> subsetStoringListB=new ArrayList<>();
List<Item[]> subsetStoringListC=new ArrayList<>();
List<Item[]> subsetStoringListD=new ArrayList<>();
List<Item[]> subsetStoringListE=new ArrayList<>();
processSubsets(categoryAItemsList.toArray(new Item[0]),2,subsetStoringListA);
processSubsets(categoryBItemsList.toArray(new Item[0]),2,subsetStoringListB);
processSubsets(categoryCItemsList.toArray(new Item[0]),2,subsetStoringListC);
processSubsets(categoryDItemsList.toArray(new Item[0]),2,subsetStoringListD);
processSubsets(categoryEItemsList.toArray(new Item[0]),1,subsetStoringListE);
System.out.println(" A groups number: "+subsetStoringListA.size());
System.out.println(" B groups number: "+subsetStoringListB.size());
System.out.println(" C groups number: "+subsetStoringListC.size());
System.out.println(" D groups number: "+subsetStoringListD.size());
System.out.println(" E groups number: "+subsetStoringListE.size());
//now we just print all possible combinations of picking a single group from each list.
//the group is an array with valid choices
// for (Item[] subsetA:subsetStoringListA){
// for (Item[] subsetB:subsetStoringListB){
// for (Item[] subsetC:subsetStoringListC){
// for (Item[] subsetD:subsetStoringListD){
// for (Item[] subsetE:subsetStoringListE){
// print(subsetA);
// print(subsetB);
// print(subsetC);
// print(subsetD);
// print(subsetE);
// System.out.println("\n");
// }
//
// }
// }
// }
// }
}
static void print(Item[] arr){
for (Item item:arr)
System.out.print(item.getDumyData()+" ");
}
static void processSubsets(Item[] set, int k,List<Item[]> subsetStoringList) {
Item[] subset = new Item[k];
processLargerSubsets(set, subset, 0, 0,subsetStoringList);
}
static void processLargerSubsets(Item[] set, Item[] subset, int subsetSize, int nextIndex,List<Item[]> subsetStoringList) {
if (subsetSize == subset.length) { //here we have a subset we need to store a copy from it
subsetStoringList.add(Arrays.copyOf(subset, subset.length));
} else {
for (int j = nextIndex; j < set.length; j++) {
subset[subsetSize] = set[j];
processLargerSubsets(set, subset, subsetSize + 1, j + 1,subsetStoringList);
}
}
}
public static enum CATEGORY_TYPE {A,B,C,D,E}
private static class Item{
private CATEGORY_TYPE categoryType;
private String dumyData;
public Item(String dumyData,CATEGORY_TYPE categoryType) {
this.dumyData = dumyData; //maybe bad name but i mean the object can have many other fields etc
this.categoryType = categoryType;
}
/**
* #return the categoryType
*/
public CATEGORY_TYPE getCategoryType() {
return categoryType;
}
/**
* #return the dumyData
*/
public String getDumyData() {
return dumyData;
}
}
}
in a specific run, it gave the following:
A groups number: 210
B groups number: 153
C groups number: 210
D groups number: 210
E groups number: 19
that means , if we had to print all possible choices of a single element (and here an elemnt is an array containing k choices from a category) from each of these, you will have : 210*153*210*210*19 = 26,921,727,000
now listing/printing over 26 billion variations will take time no matter what and I don't see how it will be minimized.
try setting the total items to 20 and uncomment the printing code to see that everything is working correctly. And see if you really need to list the possible combinations. please remember that every combination here is legal and there are no wasted iterations in all the parts of the code.
one final note: I did not treat edge cases like when there are no items in a category to complete K. that you can easily put in the code according to the desired behaviour in that case.
So this seems to be a constraint satisfaction problem. So maybe try backtracking?
I believe the following works, but plug in your own data to guaranteee.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Launch {
public static void main(String[] args) {
// Formulate the constraints.
int[] constraints = { 2, 1, 0, 1 };
// Create all the items.
List<boolean[]> items = new ArrayList<boolean[]>();
boolean[] i1 = { true, false, true, false };
boolean[] i2 = { true, false, false, false };
boolean[] i3 = { false, true, false, true };
boolean[] i4 = { false, false, false, true };
items.add(i1);
items.add(i2);
items.add(i3);
items.add(i4);
// Solve!
backtrack(constraints, items);
}
/**
* Recursively generate possible solutions but backtrack as soon as the constraints fail.
*/
private static void backtrack(int[] constraints, List<boolean[]> items) {
// We start with no items belonging to any categories.
List<List<boolean[]>> memberships = new ArrayList<List<boolean[]>>();
for (int i = 0; i < constraints.length; i++) {
memberships.add(new ArrayList<boolean[]>());
}
backtrack(constraints, items, memberships);
}
/**
* Recursively generate possible solutions but backtrack as soon as the constraints fail.
*/
private static void backtrack(int[] constraints, List<boolean[]> items,
List<List<boolean[]>> memberships) {
if (items.isEmpty() && !acceptable(constraints, memberships)) {
return;
} else if (acceptable(constraints, memberships)) {
display(memberships);
} else {
for (boolean[] item : items) {
int catIdx = 0;
for (boolean belongs : item) {
if (belongs) {
// The item and category were chosen so let's update
// memberships.
List<List<boolean[]>> newMemberships = new ArrayList<List<boolean[]>>();
for (List<boolean[]> old : memberships) {
newMemberships.add(new ArrayList<boolean[]>(old));
}
newMemberships.get(catIdx).add(item);
// We've placed the item so let's remove it from the
// possibilities.
List<boolean[]> newItems = new ArrayList<boolean[]>(
items);
newItems.remove(item);
// Now solve the sub-problem.
backtrack(constraints, newItems, newMemberships);
}
catIdx++;
}
}
}
}
/**
* A nice way to display the membership tables.
*/
private static void display(List<List<boolean[]>> memberships) {
System.out.println("---");
for (List<boolean[]> category : memberships) {
for (boolean[] item : category) {
System.out.print(Arrays.toString(item) + " ");
}
System.out.println();
}
}
/**
* Returns whether or not a list of memberships are accepted by the
* constraints.
*
* #param constraints
* - The number of items required per category.
* #param memberships
* - The current items per category.
*/
private static boolean acceptable(int[] constraints,
List<List<boolean[]>> memberships) {
boolean acceptable = memberships.size() == constraints.length;
for (int i = 0; i < memberships.size(); i++) {
acceptable = acceptable
&& constraints[i] == memberships.get(i).size();
}
return acceptable;
}
}
I have implemented two algorithms in Java and when testing depth first search it seems to be taking an incredible amount of time when there are 12 nodes, when using A* it completes it in seconds, I was just wondering if this is to be expected or am I doing something wrong? Its running the search in the background now as I type this and has been going for a few minutes.
I wouldnt normally mind but ive got to test up to 500 nodes which could take days at this rate, is this something I should expect or am I doing something wrong?
Thanks!
import java.util.*;
#SuppressWarnings({ "rawtypes", "unchecked" })
public class DepthFirstSearch {
Routes distances;
static Routes routes;
int firstNode;
String result = new String();
ArrayList firstRoute, bestRoute;
int nodes = 0;
int routeCost = 0;
int bestCost = Integer.MAX_VALUE;
public DepthFirstSearch(Routes matrix, int firstNode) { //new instance
distances = matrix;
this.firstNode = firstNode;
}
public void run () { //run algorithm
long startTime = System.nanoTime();
firstRoute = new ArrayList();
firstRoute.add(firstNode);
bestRoute = new ArrayList();
nodes++;
long endTime = System.nanoTime();
System.out.println("Depth First Search\n");
search(firstNode, firstRoute);
System.out.println(result);
System.out.println("Visited Nodes: "+nodes);
System.out.println("\nBest solution: "+bestRoute.toString() + "\nCost: "+bestCost);
System.out.println("\nElapsed Time: "+(endTime-startTime)+" ns\n");
}
/**
* #param from node where we start the search.
* #param route followed route for arriving to node "from".
*/
public void search (int from, ArrayList chosenRoute) {
// we've found a new solution
if (chosenRoute.size() == distances.getCitiesCount()) {
chosenRoute.add(firstNode);
nodes++;
// update the route's cost
routeCost += distances.getCost(from, firstNode);
if (routeCost < bestCost) {
bestCost = routeCost;
bestRoute = (ArrayList)chosenRoute.clone();
}
result += chosenRoute.toString() + " - Cost: "+routeCost + "\n";
// update the route's cost (back to the previous value)
routeCost -= distances.getCost(from, firstNode);
}
else {
for (int to=0; to<distances.getCitiesCount(); to++){
if (!chosenRoute.contains(to)) {
ArrayList increasedRoute = (ArrayList)chosenRoute.clone();
increasedRoute.add(to);
nodes++;
// update the route's cost
routeCost += distances.getCost(from, to);
search(to, increasedRoute);
// update the route's cost (back to the previous value)
routeCost -= distances.getCost(from, to);
}
}
}
}
}
you are not updating chosenRoute correctly; you always add "firstNode" with the same value to your arraylist, I think you should add the visited node.
I will try to check that later
I have an algorithm that recursively makes change in the following manner:
public static int makeChange(int amount, int currentCoin) {
//if amount = zero, we are at the bottom of a successful recursion
if (amount == 0){
//return 1 to add this successful solution
return 1;
//check to see if we went too far
}else if(amount < 0){
//don't count this try if we went too far
return 0;
//if we have exhausted our list of coin values
}else if(currentCoin < 0){
return 0;
}else{
int firstWay = makeChange(amount, currentCoin-1);
int secondWay = makeChange(amount - availableCoins[currentCoin], currentCoin);
return firstWay + secondWay;
}
}
However, I'd like to add the capability to store or print each combination as they successfully return. I'm having a bit of a hard time wrapping my head around how to do this. The original algorithm was pretty easy, but now I am frustrated. Any suggestions?
CB
Without getting into the specifics of your code, one pattern is to carry a mutable container for your results in the arguments
public static int makeChange(int amount, int currentCoin, List<Integer>results) {
// ....
if (valid_result) {
results.add(result);
makeChange(...);
}
// ....
}
And call the function like this
List<Integer> results = new LinkedList<Integer>();
makeChange(amount, currentCoin, results);
// after makeChange has executed your results are saved in the variable "results"
I don't understand logic or purpose of above code but this is how you can have each combination stored and then printed.
public class MakeChange {
private static int[] availableCoins = {
1, 2, 5, 10, 20, 25, 50, 100 };
public static void main(String[] args) {
Collection<CombinationResult> results = makeChange(5, 7);
for (CombinationResult r : results) {
System.out.println(
"firstWay=" + r.getFirstWay() + " : secondWay="
+ r.getSecondWay() + " --- Sum=" + r.getSum());
}
}
public static class CombinationResult {
int firstWay;
int secondWay;
CombinationResult(int firstWay, int secondWay) {
this.firstWay = firstWay;
this.secondWay = secondWay;
}
public int getFirstWay() {
return this.firstWay;
}
public int getSecondWay() {
return this.secondWay;
}
public int getSum() {
return this.firstWay + this.secondWay;
}
public boolean equals(Object o) {
boolean flag = false;
if (o instanceof CombinationResult) {
CombinationResult r = (CombinationResult) o;
flag = this.firstWay == r.firstWay
&& this.secondWay == r.secondWay;
}
return flag;
}
public int hashCode() {
return this.firstWay + this.secondWay;
}
}
public static Collection<CombinationResult> makeChange(
int amount, int currentCoin) {
Collection<CombinationResult> results =
new ArrayList<CombinationResult>();
makeChange(amount, currentCoin, results);
return results;
}
public static int makeChange(int amount, int currentCoin,
Collection<CombinationResult> results) {
// if amount = zero, we are at the bottom of a successful recursion
if (amount == 0) {
// return 1 to add this successful solution
return 1;
// check to see if we went too far
} else if (amount < 0) {
// don't count this try if we went too far
return 0;
// if we have exhausted our list of coin values
} else if (currentCoin < 0) {
return 0;
} else {
int firstWay = makeChange(
amount, currentCoin - 1, results);
int secondWay = makeChange(
amount - availableCoins[currentCoin],
currentCoin, results);
CombinationResult resultEntry = new CombinationResult(
firstWay, secondWay);
results.add(resultEntry);
return firstWay + secondWay;
}
}
}
I used the following:
/**
* This is a recursive method that calculates and displays the combinations of the coins included in
* coinAmounts that sum to amountToBeChanged.
*
* #param coinsUsed is a list of each coin used so far in the total. If this branch is successful, we will add another coin on it.
* #param largestCoinUsed is used in the recursion to indicate at which coin we should start trying to add additional ones.
* #param amountSoFar is used in the recursion to indicate what sum we are currently at.
* #param amountToChange is the original amount that we are making change for.
* #return the number of successful attempts that this branch has calculated.
*/private static int change(List<Integer> coinsUsed, Integer currentCoin, Integer amountSoFar, Integer amountToChange)
{
//if last added coin took us to the correct sum, we have a winner!
if (amountSoFar == amountToChange)
{
//output
System.out.print("Change for "+amountToChange+" = ");
//run through the list of coins that we have and display each.
for(Integer count: coinsUsed){
System.out.print(count + " ");
}
System.out.println();
//pass this back to be tallied
return 1;
}
/*
* Check to see if we overshot the amountToBeChanged
*/
if (amountSoFar > amountToChange)
{
//this branch was unsuccessful
return 0;
}
//this holds the sum of the branches that we send below it
int successes=0;
// Pass through each coin to be used
for (Integer coin:coinAmounts)
{
//we only want to work on currentCoin and the coins after it
if (coin >= currentCoin)
{
//copy the list so we can branch from it
List<Integer> copyOfCoinsUsed = new ArrayList<Integer>(coinsUsed);
//add on one of our current coins
copyOfCoinsUsed.add(coin);
//branch and then collect successful attempts
successes += change(copyOfCoinsUsed, coin, amountSoFar + coin, amountToChange);
}
}
//pass back the current
return successes;
}