I'm struggling with this problem on HackerRank.
https://www.hackerrank.com/challenges/friend-circle-queries/problem
I tried solving it using a custom linked list - NodeList. It has three fields - Node first, Node current, int size. 'add' is an overloaded method. It can add a value or another NodeList.
I have put code for NodeList in comments because it doesn't matter much.
Fields :-
static HashMap<Integer, Integer> personToIndex = new HashMap<>();
static int largestCircleSize = 0;
static ArrayList<NodeList> groups = new ArrayList<>();
This is my business logic method.
When only one person is part of a friend circle, I add the other person in the circle. When both the people who are shaking hands are already part of other circles, I merge the circles.
static void updateFriendCircles(int friend1, int friend2) {
int friend1Index, friend2Index;
NodeList toUpdate;
friend1Index = personToIndex.getOrDefault(friend1, -1);
friend2Index = personToIndex.getOrDefault(friend2, -1);
if (friend1Index != -1) {
NodeList list = groups.get(friend1Index);
if (friend2Index != -1) {
NodeList list2 = groups.get(friend2Index);
if (list.first == groups.get(friend2Index).first)
return;
toUpdate = list.add(list2);
groups.set(friend2Index, list);
}
else {
toUpdate = list.add(friend2);
personToIndex.put(friend2, friend1Index);
}
}
else if (friend2Index != -1) {
toUpdate = groups.get(friend2Index).add(friend1);
personToIndex.put(friend1, friend2Index);
}
else {
int index = groups.size();
personToIndex.put(friend1, index);
personToIndex.put(friend2, index);
toUpdate = new NodeList(friend1).add(friend2);
groups.add(toUpdate);
}
if (toUpdate.size > largestCircleSize)
largestCircleSize = toUpdate.size;
}
I have also tried using HashSet but it also has same problem so I think problem is not in data structure.
As it's not clear what is wrong with the solution exactly (it's not specified by the OP) - wrong answers or timeout for some test cases I'll explain how to solve it.
We can use a disjoint set data structure to represent sets of friend circles.
The basic idea is that in each circle we assign a member that is used to represent a given circle. We can call it a root. Finding a number of members in the circle is always delegated to the root that stores its size.
Each non-root member points to his root member or to a member through whom he can get to the root. In the future, the current root may also lose his root status for the community but then it will point to the new root and so it's always possible to get to it through chained calls.
When 2 circles merge then a new root member is chosen among 2 previous ones. The new size can be set into it because previous roots already contain sizes for both circles. But how is the new root chosen? If the size of circle 1 is not smaller than that of circle 2 then it's picked as a new root.
So, for this problem, first we should define placeholders for circles and sizes:
Map<Integer, Integer> people;
Map<Integer, Integer> sizes;
For non-root members in people, key is a person ID and value is a friend he follows (root or parent that can get him to the root). Root members won't have an entry in the map.
Then, we need a method that will get us to the root for any member:
int findCommunityRoot(int x) {
if (people.containsKey(x)) {
return findCommunityRoot(people.get(x));
}
return x;
}
Finally, we need a method to build a community for 2 given friends:
int mergeCommunities(int x, int y) {
//find a root of x
x = findCommunityRoot(x);
//find a root of y
y = findCommunityRoot(y);
// one-man circle has a size of 1
if (!sizes.containsKey(x)) {
sizes.put(x, 1);
}
// one-man circle has a size of 1
if (!sizes.containsKey(y)) {
sizes.put(y, 1);
}
// friends in the same circle so just return its size
if (x == y) {
return sizes.get(x);
}
sizeX = sizes.get(x);
sizeY = sizes.get(y);
if (sizeX >= sizeY) {
people.put(y, x);
sizes.put(x, sizeY + sizeX);
return sizes.get(x);
} else {
people.put(x, y);
sizes.put(y, sizeY + sizeX);
return sizes.get(y);
}
}
So, we have everything we need to save a size of the largest circle at each iteration:
List<Integer> maxCircle(int[][] queries) {
List<Integer> maxCircles = new ArrayList<>();
int maxSize = 1;
for (int i = 0; i < queries.length; i++) {
int size = mergeCommunities(queries[i][0], queries[i][1]);
maxSize = Math.max(maxSize, size);
maxCircles.add(maxSize);
}
return maxCircles;
}
Related
I wrote an algorithms for testing graph bipartitness for Graph Algorithms course on edX (initially available on Coursera) and it fails on one of their test cases.
I gave it a thought and cannot find so far what might I be missing, I use BFS traversal to color nodes to test for bipartitness, it works on a few simple test cases and on 17 of 28 test cases on edX.
private static final int WHITE = -1;
private static final int BLACK = -2;
private static final int START_INDEX = 0;
static boolean isBipartite(ArrayList<Integer>[] adj) { // an array of lists of neighbors
int[] colors = new int[adj.length];
boolean[] visited = new boolean[adj.length];
colors[START_INDEX] = WHITE;
Queue<Integer> queue = new LinkedList<>();
// start with some node
queue.add(START_INDEX);
while (!queue.isEmpty()) {
int node = queue.poll();
ArrayList<Integer> neighbors = adj[node];
for (int neighbor : neighbors) {
if (!visited[neighbor]) {
if (node != neighbor) {
// add for traversal and color with an opposite color
queue.add(neighbor);
colors[neighbor] = colors[node] == WHITE ? BLACK : WHITE;
} else {
// self cycle will always be odd
return false;
}
} else {
// return immediately if encountered an already colored node
// with the same color, there is an odd cycle
if (colors[node] == colors[neighbor]) {
return false;
}
}
}
visited[node] = true;
}
// final check of u and v colors for all edges
for (int u = 0; u < adj.length; u++) {
for (int i = 0; i < adj[u].size(); i++) {
int v = adj[u].get(i);
if (colors[u] == colors[v]) {
return false;
}
}
}
return true;
}
Any suggesting what could I be missing in my algorithm?
Also without the final check my algorithm would fail on the 3rd test case out of 28 (I do not see the inputs), even though I don't understand why - I should already be finding the odd cycles in the main for loop.
Please help.
Some of the sample graphs I tested myself, the 1st is not bipartite, the 2nd is bipartite.
As has been noted in the comments, you assume that every node is reachable from the starting node. The good news is that this is quite easy to fix. Define an enum Colors of three values: NoColor, Black, and White. The pseudocode goes as follows:
Input: graph G with nodes integers from 0 to n - 1
Initialise array colors of length n with all values set to NoColor;
for each `i` from `0` to `n - 1`, do {
if colors[i] = NoColor then {
Initialise q to an empty queue (or stack - whatever floats your boat);
push i onto queue;
colors[i] <- Black;
while q is not empty do {
pop k off of q;
for each neighbour i of k such that colors[i] = NoColor do
colors[i] <- the opposite color of colors[k];
push i onto q;
}
}
}
}
This gives you the 2-coloring, if the coloring exists. In this case, you'll want to verify that it is in fact a 2-coloring to check if the graph is bipartite.
For a project I want to generate a tree structure which has x children and is n 'layers' deep. A layer can the best be described in the following figure:
0
1 1
2 2 2 2
The number on each row equals the layer number.
I got the following class named Node:
public class Node {
private String nodeName;
private List<Node> children;
private int layer;
/**
* A node with a name and a list of children on a given layer in a tree or
* web
*
* #param nodeName the name of the node
* #param children the list of children of this node
* #param layer the layer in which this node exists
*/
public Node(String nodeName, List<Node> children, int layer) {
this.nodeName = nodeName;
this.children = children;
this.layer = layer;
}
}
Additionally, I have getters and setters for each field.
After struggling for two full evenings, I came up with this code:
private static Node createTree() {
Node masterNode = new Node();
int childsPerNode = 3;
int amountOfLayers = 5; //meaning 6 layers, 0 is included
//Output = 364
int totalNodeAmount = calculateNodeAmount(childsPerNode, amountOfLayers);
//Loop for each layer, form bottom to top
for (int currentLayer = 5; currentLayer > amountOfLayers; currentLayer--) {
/**
* For each layer, calculate the nodes for this layer, add children
* to each node
*/
int nodesThisLayer = calculateNodeAmount(childsPerNode, amountOfLayers) - calculateNodeAmount(childsPerNode, currentLayer);
for (int nodeCount = 0; nodeCount < nodesThisLayer; nodeCount++) {
List<Node> children = new ArrayList<>();
for (int childCount = 0; childCount < childsPerNode; childCount++) {
String childFunctionName = "name";
Node childNode = new Node(childFunctionName, null, currentLayer);
children.add(childNode);
}
String parentFunctionName = "parent name";
Node parentNode = new Node(parentFunctionName, children, currentLayer);
}
}
return masterNode;
}
Any help regarding my way to end up with one Node which contains the whole tree in its children is greatly appreciated, as I'm out of ideas. I did not find a good source for a tree with x children and n layers (or depth), hence my potential double question.
Kind regards!
EDIT:
Based on the comment of lexicore, I came up with this function:
private static void createTree(Node currentNode, int childrenPerNode, int numberOfLayers) {
if (numberOfLayers == 0) {
//Something is off here
return;
} else if (numberOfLayers > 0) {
//Create sub nodes
List<Node> nodes = new ArrayList<>();
for (int i = 0; i < childrenPerNode; i++) {
Node childNode = new Node("name", nodes, numberOfLayers);
nodes.add(childNode);
}
//Add the children to the current node
currentNode.setChilderen(nodes);
for (int i = 0; i < childrenPerNode; i++) {
//For each of the children per node, call this function again until the number of layers equals zero
createTree(currentNode.getChildren().get(i), childrenPerNode, numberOfLayers - 1);
}
}
This does, however, continue too loop way too 'deep' (too much layers). I'm breaking my head on why that is.
I'll be looking to the other answers right now. Thanks for your time already!
The title says "recursive," so I'll assume you really want to write a recursive method. To write one, you must learn to think recursively.
For the task of building trees, this is pretty straightforward. Trees are recursively defined: a tree may be empty or else a node with trees as children.
In your case the definition is a bit more complicated. A layer N tree may be empty (if N is greater than or equal to the max desired layer number) or else it's a node with layer number N and K subtrees with layer number N+1.
This translates to an algorithm:
Node buildTree(int N) {
// A layer N tree may be empty (if N is more than the max desired layer number)
if (L >= maxLayerNumber) {
return new Node with no children
}
// ... or else it's a node with layer number N and K subtrees with layer number N+1
Let C be an initially empty list of children
for i = 1 to K {
Let c = buildTree(N + 1)
Add c to C
}
return new Node with layer number N and children C
}
To get the whole tree, call buildTree(0).
I'm deliberately not providing Java code. It's important to solve problems yourself.
You might want to avoid calculating the number of children you'll need to create by either using recursion as suggested in the comments or by iterating through the bottom nodes of the tree and keeping them in a separate collection.
List<Node> children = new ArrayList<Node>();
children.add(masterNode);
int layer = amountOfLayers;
while (layer > 0) {
List<Node> allBottomChildren = new ArrayList<Node>();
for (Node child : children) {
List<Node> nextLevelChildren = new ArrayList<Node>();
for (int i = 0;i<childsPerNode;i++) {
Node node = new Node("name", new ArrayList<Node>(), layer - 1);
nextLevelChildren.add(node);
}
child.setChildren(nextLevelChildren);
allBottomChildren.addAll(nextLevelChildren);
}
children = allBottomChildren;
layer = layer - 1;
}
This is obviously not the best design, but a pretty brief solution:
int childsPerNode = 3;
int amountOfLayers = 5;
class AutoNode {
int layer;
List <AutoNode> childs;
public AutoNode (int n) {
layer = n;
if (layer < amountOfLayers) {
childs = new ArrayList<AutoNode> ();
for (int i = 0; i < childsPerNode; ++i) {
childs.add (new AutoNode (n + 1));
}
}
}
public String toString () {return ("layer: " + layer + " <" + ((layer < 5) ? childs.toString () : "()") + ">" );}
}
AutoNode root = new AutoNode (0);
The bounds:
int childsPerNode = 3;
int amountOfLayers = 5;
are somewhat alien to the Nodes. But it works as a first, quick prototype.
You can add methods to the Autonode, and perform different exercises. You may put them as final static into the Autonode definition.
If you want to heat up System, call root with = new AutoNode (-40); but calculate 3^45 first.
Here's an example of a fully encapsulated object-oriented design (i.e. recursive constructor):
public class Tree
{
private int layer;
private int nodeID;
private List<Tree> children;
public Tree(int numOfchildren, int numOfLayers)
{
this(numOfchildren, numOfLayers, 0, new int[1]);
}
private Tree(int numOfchildren, int numOfLayers, int layerIndex, int[] nodeIndex)
{
layer = layerIndex;
nodeID = nodeIndex[0]++;
if (numOfLayers > 0 && numOfchildren > 0) {
children = new ArrayList<Tree> ();
for (int i = 0; i < numOfchildren; i++) {
children.add(new Tree(numOfchildren, numOfLayers - 1, layer + 1, nodeIndex));
}
}
}
}
Some noteworthy concepts:
The Tree class contains one public constructor and one private constructor. The public constructor in just a "clean" interface. The private one does all the "dirty" work.
The layerIndex parameter of the private constructor sets the offset of the root node. Setting it to 0 (as does the public constructor) is best.
The int[] nodeIndex array parameter of the private constructor is a "workaround" for sending an int argument by reference. The array argument (as provided by the public constructor) consists of a single element array that keeps track of the number of children created thus far in order to set the nodeID to a unique value.
We need to compute the minCost(), which has follwing parameters:
gNodes - no of Nodes in graph g.
an array of int's, gFrom, where each gfrom[i] denotes a node connected by ith edge in graph g.
an array of int's, gTo, where each gTo[i] denotes a node connected by ith edge in graph g.
an array of int's, gWeight, denoting the respective weights of each edge in graph g.
an int, start, denoting the start node index.
an int, end, denoting the end node index.
an integer, wExtra, denoting the weight of optional extra edge.
We need to find the path from start to end having minimum possible weight. We can add at most one extra edge(ie. zero or one) having wExtra weight between any two distinct nodes that are not already connected by an edge. The function must return an int denoting the minimum path weight from start to end.
I was able to come up with following code (Dijkstra algorithm) but it doesn't give the expected output.
public static int minCost(int gNodes, int[] gFrom, int[] gTo, int[] gWeights, int start, int end) {
//making a array to store shortest length and filling it with infinity except the first one
int[] shortest = new int[gNodes];
for (int i = 0; i < gNodes; i++) {
shortest[i] = Integer.MAX_VALUE;
}
shortest[start]=0;
//filling the Queue with all vertices
Queue<Integer> theQ = new PriorityQueue<>();
for (int i = 0; i < gNodes; i++) {
theQ.add(i + 1);
}
//following the algorithm
while (!theQ.isEmpty()) {
int u = theQ.poll();
//making a list of adjacent vertices
List<Integer> adjacent = new ArrayList<>();
for (int i = 0; i < gFrom.length; i++) {
if (gFrom[i] == u) {
adjacent.add(gTo[i]);
} else if (gTo[i] == u) {
adjacent.add(gFrom[i]);
}
}
for (int v: adjacent) {
int weight=0;
for (int i = 0; i < gFrom.length; i++) {
if ((gFrom[i] == u && gTo[i] == v) || (gFrom[i] == v && gTo[i] == u)) {
weight = gWeights[i];
}
}
//relaxing the verices
if (shortest[v] > shortest[u] + weight) {
shortest[v] = shortest[u] + weight;
}
if (v == end) {
return shortest[v];
}
theQ.add(v);
}
}
return -1;
}
public static void main(String[] args) {
int gNodes = 4;
int[] gFrom = {1, 2, 2, 3};
int[] gTo = {2, 3, 4, 4};
int[] gWeights = {2, 1, 2, 3};
int start =1;
int end = 4;
System.out.println(shortestDistance(gNodes, gFrom, gTo, gWeights, start, end));
}
}
It's not giving the expected output which I think is because I can't think of how to use that wExtra. Also, the code is quite messy. Please let me know what's wrong or feel free to provide any robust code that does it well. Thanks.
A possible idea to integrate wExtra is the following:
Duplicate the graph, such that you have two nodes for every input node. The original graph represents the state before introducing the new edge. The copy represents the state after the introduction. For every node n in the original graph, you should then introduce directed edges with weight wExtra to all nodes m in the copy, where the original of m is not adjacent to n. This basically represents the fact that you can introduce a new edge between any two non-adjacent edges. But once you have done this, you cannot go back. Then, run usual Dijkstra on the modified graph between start and either the original end or the copy of end and you should get the correct result.
The best way to visualize this is probably to interpret the two sub graphs as layers. You start at the original layer and want to get to one of the two end nodes (whichever is closer). But you may switch layers only once.
I have an undirected graph with positive edge weights. I am given a start point and the maximum amount of distance I can travel, and in the end, I must return to the start point. What sort of algorithm can do this for me, and give me the path that results?
I understand java well, so if you can, please make code samples look similar to java.
Like I said a DFS should do the trick, this sample code gives the idea. But beware, this sample code don't handle cyclic reference, you will have to do that
public class Answer {
private static final int MAX_WEIGHT = 11;
public static void main(String[] args) {
Node node1 = new Node("node 1");
Node node1_1 = new Node("node 1-1");
Node node1_1_1 = new Node("node 1-1-1");
Node node1_2 = new Node("node 1-2");
Node node1_2_1 = new Node("node 1-2-1");
Node node1_2_1_1 = new Node("node 1-2-1-1");
node1.addNeighbour(node1_1, 1);
node1_1.addNeighbour(node1_1_1, 2);
node1.addNeighbour(node1_2, 1);
node1_2.addNeighbour(node1_2_1, 2);
node1_2_1.addNeighbour(node1_2_1_1, 3);
System.out.println("max of nodes = " + travel(node1, 0));
}
private static int travel(Node node, int totalWeight) {
int maxNodes = 1;
for (Map.Entry<Node, Integer> entry : node.neighbours.entrySet()) {
Integer weight = entry.getValue();
int nodes = 1;
if ((totalWeight + weight) * 2 <= MAX_WEIGHT) {
nodes += travel(entry.getKey(), totalWeight + weight);
}
if (nodes > maxNodes) {
maxNodes = nodes;
}
}
return maxNodes;
}
}
class Node {
String id;
Map<Node, Integer> neighbours;
public Node(String id) {
this.id = id;
neighbours = new HashMap<Node, Integer>();
}
public void addNeighbour(Node node, int weight) {
neighbours.put(node, weight);
}
#Override
public String toString() {
final StringBuilder sb = new StringBuilder("Node{");
sb.append("id='").append(id).append('\'');
sb.append(", neighbours=").append(neighbours);
sb.append('}');
return sb.toString();
}
}
I now realise this is still NP-hard, even if vertices can be visited more than once: Hamiltonian Path is NP-hard even on unweighted graphs, so we are free to create an instance of your problem using arbitrarily chosen weights. Specifically, given an instance (G = (V, E), k) of Hamiltonian Path, we can create an instance (G' = (V', E'), w, s, d) of your problem in which:
V' = V, plus a new vertex, s
E' = E, plus the edge (s, u) for every vertex u in V
The weight w(e) of every edge e in E' is 1
The starting point is s
The maximum total travel distance is |V|+1.
If the solution to this instance is |V|+1 distinct vertices, then clearly it contains every vertex in G' exactly once, so removing the vertex s from the cycle will leave a path through all the remaining vertices, i.e., a Hamiltonian path in the original graph G. If the solution to this instance is less than |V|+1, then no Hamiltonian path exists in G -- since if one did, we would indeed have gotten a solution of |V|+1.
So, if your problem could be solved in polynomial time, then so could an NP-complete problem. That means that it's very unlikely that your problem can be solved in polynomial time.
I'm trying to implement a program to solve the n-puzzle problem.
I have written a simple implementation in Java that has a state of the problem characterized by a matrix representing the tiles. I am also able to auto-generate the graph of all the states giving the starting state. On the graph, then, I can do a BFS to find the path to the goal state.
But the problem is that I run out of memory and I cannot even create the whole graph.
I tried with a 2x2 tiles and it works. Also with some 3x3 (it depends on the starting state and how many nodes are in the graph). But in general this way is not suitable.
So I tried generating the nodes at runtime, while searching. It works, but it is slow (sometimes after some minutes it still have not ended and I terminate the program).
Btw: I give as starting state only solvable configurations and I don't create duplicated states.
So, I cannot create the graph. This leads to my main problem: I have to implement the A* algorithm and I need the path cost (i.e. for each node the distance from the starting state), but I think I cannot calculate it at runtime. I need the whole graph, right? Because A* does not follow a BFS exploration of the graph, so I don't know how to estimate the distance for each node. Hence, I don't know how to perform an A* search.
Any suggestion?
EDIT
State:
private int[][] tiles;
private int pathDistance;
private int misplacedTiles;
private State parent;
public State(int[][] tiles) {
this.tiles = tiles;
pathDistance = 0;
misplacedTiles = estimateHammingDistance();
parent = null;
}
public ArrayList<State> findNext() {
ArrayList<State> next = new ArrayList<State>();
int[] coordZero = findCoordinates(0);
int[][] copy;
if(coordZero[1] + 1 < Solver.SIZE) {
copy = copyTiles();
int[] newCoord = {coordZero[0], coordZero[1] + 1};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
if(coordZero[1] - 1 >= 0) {
copy = copyTiles();
int[] newCoord = {coordZero[0], coordZero[1] - 1};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
if(coordZero[0] + 1 < Solver.SIZE) {
copy = copyTiles();
int[] newCoord = {coordZero[0] + 1, coordZero[1]};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
if(coordZero[0] - 1 >= 0) {
copy = copyTiles();
int[] newCoord = {coordZero[0] - 1, coordZero[1]};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
return next;
}
private State checkNewState(int[][] tiles) {
State newState = new State(tiles);
for(State s : Solver.states)
if(s.equals(newState))
return null;
return newState;
}
#Override
public boolean equals(Object obj) {
if(this == null || obj == null)
return false;
if (obj.getClass().equals(this.getClass())) {
for(int r = 0; r < tiles.length; r++) {
for(int c = 0; c < tiles[r].length; c++) {
if (((State)obj).getTiles()[r][c] != tiles[r][c])
return false;
}
}
return true;
}
return false;
}
Solver:
public static final HashSet<State> states = new HashSet<State>();
public static void main(String[] args) {
solve(new State(selectStartingBoard()));
}
public static State solve(State initialState) {
TreeSet<State> queue = new TreeSet<State>(new Comparator1());
queue.add(initialState);
states.add(initialState);
while(!queue.isEmpty()) {
State current = queue.pollFirst();
for(State s : current.findNext()) {
if(s.goalCheck()) {
s.setParent(current);
return s;
}
if(!states.contains(s)) {
s.setPathDistance(current.getPathDistance() + 1);
s.setParent(current);
states.add(s);
queue.add(s);
}
}
}
return null;
}
Basically here is what I do:
- Solver's solve has a SortedSet. Elements (States) are sorted according to Comparator1, which calculates f(n) = g(n) + h(n), where g(n) is the path cost and h(n) is a heuristic (the number of misplaced tiles).
- I give the starting configuration and look for all the successors.
- If a successor has not been already visited (i.e. if it is not in the global set States) I add it to the queue and to States, setting the current state as its parent and parent's path + 1 as its path cost.
- Dequeue and repeat.
I think it should work because:
- I keep all the visited states so I'm not looping.
- Also, there won't be any useless edge because I immediately store current node's successors. E.g.: if from A I can go to B and C, and from B I could also go to C, there won't be the edge B->C (since path cost is 1 for each edge and A->B is cheaper than A->B->C).
- Each time I choose to expand the path with the minimum f(n), accordin to A*.
But it does not work. Or at least, after a few minutes it still can't find a solution (and I think is a lot of time in this case).
If I try to create a tree structure before executing A*, I run out of memory building it.
EDIT 2
Here are my heuristic functions:
private int estimateManhattanDistance() {
int counter = 0;
int[] expectedCoord = new int[2];
int[] realCoord = new int[2];
for(int value = 1; value < Solver.SIZE * Solver.SIZE; value++) {
realCoord = findCoordinates(value);
expectedCoord[0] = (value - 1) / Solver.SIZE;
expectedCoord[1] = (value - 1) % Solver.SIZE;
counter += Math.abs(expectedCoord[0] - realCoord[0]) + Math.abs(expectedCoord[1] - realCoord[1]);
}
return counter;
}
private int estimateMisplacedTiles() {
int counter = 0;
int expectedTileValue = 1;
for(int i = 0; i < Solver.SIZE; i++)
for(int j = 0; j < Solver.SIZE; j++) {
if(tiles[i][j] != expectedTileValue)
if(expectedTileValue != Solver.ZERO)
counter++;
expectedTileValue++;
}
return counter;
}
If I use a simple greedy algorithm they both work (using Manhattan distance is really quick (around 500 iterations to find a solution), while with number of misplaced tiles it takes around 10k iterations). If I use A* (evaluating also the path cost) it's really slow.
Comparators are like that:
public int compare(State o1, State o2) {
if(o1.getPathDistance() + o1.getManhattanDistance() >= o2.getPathDistance() + o2.getManhattanDistance())
return 1;
else
return -1;
}
EDIT 3
There was a little error. I fixed it and now A* works. Or at least, for the 3x3 if finds the optimal solution with only 700 iterations. For the 4x4 it's still too slow. I'll try with IDA*, but one question: how long could it take with A* to find the solution? Minutes? Hours? I left it for 10 minutes and it didn't end.
There is no need to generate all state space nodes for solving a problem using BFS, A* or any tree search, you just add states you can explore from current state to the fringe and that's why there is a successor function.
If BFS consumes much memory it is normal. But I don't know exactly fro what n it would make problem. Use DFS instead.
For A* you know how many moves you made to come to current state and you can estimate moves need to solve problem, simply by relaxing problem. As an example you can think that any two tiles can replace and then count moves needed to solve the problem. You heuristic just needs to be admissible ie. your estimate be less then actual moves needed to solve the problem.
add a path cost to your state class and every time you go from a parent state P to another state like C do this : c.cost = P.cost + 1 this will compute the path cost for every node automatically
this is also a very good and simple implementation in C# for 8-puzzle solver with A* take a look at it you will learn many things :
http://geekbrothers.org/index.php/categories/computer/12-solve-8-puzzle-with-a