Minimum Cost Path with Left, Right, Bottom and Up moves allowed - algorithm
Problem Statement:
Given a square grid of size N, each cell of which contains integer cost which represents a cost to traverse through that cell, we need to find a path from top left cell to bottom right cell by which the total cost incurred is minimum.
From the cell (i,j) we can go (i,j-1), (i, j+1), (i-1, j), (i+1, j).
Note: It is assumed that negative cost cycles do not exist in the input matrix.
Below is the code that I have written:
class Coordinate {
int x;
int y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Coordinate other = (Coordinate) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
}
public class MinCostPath {
public static int minimumCostPath(int[][] grid) {
int R = grid.length;
int C = grid[0].length;
int[][] dist = new int[R][C];
for (int i = 0; i < R; i++) {
for (int j = 0; j < C; j++) {
dist[i][j] = Integer.MAX_VALUE;
}
}
dist[0][0] = grid[0][0];
Queue<Coordinate> q = new LinkedList<>();
q.add(new Coordinate(0, 0));
int[] x = { -1, 1, 0, 0 };
int[] y = { 0, 0, 1, -1 };
while (!q.isEmpty()) {
Coordinate current = q.poll();
for (int i = 0; i < 4; i++) {
int xi = current.getX() + x[i];
int yi = current.getY() + y[i];
if (isSafe(xi, yi, R, C)) {
if (dist[xi][yi] > dist[current.getX()][current.getY()] + grid[xi][yi]) {
dist[xi][yi] = dist[current.getX()][current.getY()] + grid[xi][yi];
Coordinate c = new Coordinate(xi, yi);
if (!q.contains(c))
q.add(c);
}
}
}
}
return dist[R - 1][C - 1];
}
private static boolean isSafe(int xi, int yi, int r, int c) {
return (xi >= 0) && (xi < r) && (yi >= 0) && (yi < c);
}
public static void main(String[] args) {
int[][] grid = { { 9, 4, 9, 9 }, { 6, 7, 6, 4 }, { 8, 3, 3, 7 }, { 7, 4, 9, 10 } };
System.out.println(minimumCostPath(grid));
}
}
It gives 'Runtime Error:Time Limit Exceeded' Error
Below is an article from geeksforgeeks that has the solution.
Minimum Cost Path Problem
What I am not able to understand is why my code is giving 'Time Limit Exceeded' Error while the solution mentioned in the article is working. To my understanding, both the solutions are doing exactly the same thing.
Please help me understand the difference and what optimization is needed in the code that I have written. Thanks in Advance.
It seems from your implementation that you are trying to use Breadth First Search instead of Dijkstra which is the right approach to solve this.
You need to use a priority queue and a map to trace your path.
Also for BFS typically you don't need to do if (! q.contains(node)) that actually unnecessarily consumes time.
what optimization is needed in the code
The problem needs to be reformulated so you can apply the Dijkstra algorithm ( https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm )
That algorithm assumes the links are costed, rather than the nodes ( cells ). Consider two adjacent cells with traversal costs c and d. Travelling from the first to the second adds cost d. Travelling from the second to the first adds cost c. So you can connect the two cells with two unidirectional links of cost c and d. The Dijkstra algorithm will give you the correct cost when the entire path is travelled, minus the the traversal cost of the first cell - which is a constant and can therefor be ignored when finding the optimal path.
I use the boost graph implementation of Dijkstra, which is fast and well tested ( https://www.boost.org/doc/libs/1_76_0/libs/graph/doc/dijkstra_shortest_paths.html ). The API is a challenge if you haven't used the boost library before, so I use a C++ style wrapper to simplify coding ( https://github.com/JamesBremner/PathFinder )
Here is the output from PathFinder on the sample problem you posted
C:\Users\James\code\PathFinder\bin>mazes ..\dat\vivekkumar.txt
Mazes
cellcosts
s9 4 9 9
6 7 6 4
8 3 3 7
7 4 9 e10
4 by 4
0 -> 1 -> 5 -> 9 -> 10 -> 11 -> 15 ->
+---+---+---+---+
| s * |
+ + + + +
| * |
+ + + + +
| * * * |
+ + + + +
| e |
+---+---+---+---+
Related
2D Nearest Neighbor Search
Starting from the green square, I want an efficient algorithm to find the nearest 3 x 3 window with no red squares, only blue squares. The algorithm doesn't need to find exactly the closest 3 x 3 window, but it should find a 3 x 3 all-blue window close to the green square (assuming one exists). I thought about implementing this as a recursive breadth-first search, but that solution would involve re-checking the same square many times. Posting this to see if someone knows of a more efficient solution. Cost to check a given square is constant and cheap, but I want to minimize the execution time of the algorithm as much as possible (practical application of this will involve finding a 3x3 "clear" / all-blue window within a much larger 2D search area). Here's an example solution, but I don't think it's optimal. It's actually a depth-first search that I will have to restructure to convert to a breadth-first, but I need to think a bit more about how to do that (one way would be to make each point an object that expands to neighboring points, then iterate multiple times across those points to children, visit those children before allowing those children to generate more children). Point is that I think there's a more efficient and common way to do this so I'm trying to avoid reinventing the wheel. public class Search2D { private TreeSet<Point> centerpointscheckedsofar; private Point Search(Point centerpoint) { if(centerpointscheckedsofar.contains(centerpoint)) { return null; } if(isWithinBounds(centerpoint)) { if(checkCenterPoint(centerpoint)) { centerpointscheckedsofar.add(centerpoint); return null; } Point result = Search(getPoint(-1, -1, centerpoint)); if(result != null) return result; result = Search(getPoint(-1, 0, centerpoint)); if(result != null) return result; result = Search(getPoint(-1, 1, centerpoint)); if(result != null) return result; result = Search(getPoint(0, -1, centerpoint)); if(result != null) return result; result = Search(getPoint(0, 1, centerpoint)); if(result != null) return result; result = Search(getPoint(1, -1, centerpoint)); if(result != null) return result; result = Search(getPoint(1, 0, centerpoint)); if(result != null) return result; result = Search(getPoint(1, 1, centerpoint)); if(result != null) return result; } return null; } private Point getPoint(int x, int y, Point centerpoint) { return new Point(centerpoint.x + x, centerpoint.y + y); } private boolean checkCenterPoint(Point centerpoint) { //check here to see if point is valid return false; } private boolean isWithinBounds(Point startPoint) { //check here to see if point and all neighboring points of 3 x 3 window falls within bounds return false; } } UPDATE: Distance measure is not that important, but for simplicity, let's minimize Manhattan distance. Here's a better algorithm that does not use recursion and will be guaranteed to find the closest solution (or one of the closest solutions if there is a tie). It needs a grid greater than 5 x 5 to work properly, but if you want to search a grid smaller than that, there's probably a more efficient algorithm that can be used. Assumes lowest x-index is 0 and lowest y-index is also 0. import java.awt.Point; public class Search2D_v2 { private boolean[][] bitgrid; public Search2D_v2() { bitgrid = new boolean[20][20]; } public Point search(int centerx, int centery, int maxx, int maxy, int maxsearchsteps) { //check starting point first, if it works, we're done if(checkPoint(centerx, centery)) { return new Point(centerx, centery); } int westbound = centerx-1; boolean keepgoingwest = true; int eastbound = centerx+1; boolean keepgoingeast = true; int southbound = centery-1; boolean keepgoingsouth = true; int northbound = centery+1; boolean keepgoingnorth = true; //stay within bounds, may move initial search square by 1 east and 1 west if(westbound <= 0) { eastbound = 3; westbound = 1; } if(eastbound >= maxx) { eastbound = maxx - 1; westbound = maxx - 3; } if(southbound == 0) { northbound = 3; southbound = 1; } if(northbound == maxy) { northbound = maxy - 1; southbound = maxy - 3; } //always search boundary, we've already searched inside the boundary on previous iterations, expand boundary by 1 step / square for each iteration for(int i = 0; i < maxsearchsteps && (keepgoingwest || keepgoingeast || keepgoingsouth || keepgoingnorth); i++) { //search top row if(keepgoingnorth) { //if we have already hit the north bound, stop searching the top row for(int x = westbound; x <= eastbound; x++) { if(checkPoint(x, northbound)) { return new Point(x, northbound); } } } //search bottom row if(keepgoingsouth) { for(int x = westbound; x <= eastbound; x++) { if(checkPoint(x, southbound)) { return new Point(x, southbound); } } } //search westbound if(keepgoingwest) { for(int y = southbound; y <= northbound; y++) { if(checkPoint(westbound, northbound)) { return new Point(westbound, y); } } } //search eastbound if(keepgoingeast) { for(int y = southbound; y <= northbound; y++) { if(checkPoint(eastbound, northbound)) { return new Point(eastbound, y); } } } //expand search area by one square on each side if(westbound - 2 >= 0) { westbound--; } else { keepgoingwest = false; } if(eastbound + 2 <= maxx) { eastbound++; } else { keepgoingeast = false; } if(southbound - 2 >= 0) { southbound--; } else { keepgoingsouth = false; } if(northbound + 2 <= maxy) { northbound++; } else { keepgoingnorth = false; } } return null; //failed to find a point } private boolean checkPoint(int centerx, int centery) { return !bitgrid[centerx][centery] && //center !bitgrid[centerx-1][centery-1] && //left lower !bitgrid[centerx-1][centery] && //left middle !bitgrid[centerx-1][centery+1] && //left upper !bitgrid[centerx][centery-1] && //middle lower !bitgrid[centerx][centery+1] && //middle upper !bitgrid[centerx+1][centery-1] && //right lower !bitgrid[centerx+1][centery] && //right middle !bitgrid[centerx+1][centery+1]; //right upper } }
A simple advice would be to mark all the cells you have checked. That way you won't have to check the cells multiple times. Recursion will definitely take more time than an iteration based approach since it will create a new stack each time you make a new call. If you are trying to find the closest one, prefer BFS over DFS. I would also suggest making a quick internet research for "Flood Fill Algorithm".
You could spiral outwards from your starting pixel. Whenever you encounter a pixel p that has not been checked, examine the 3x3 environment around p. For each red pixel r in the environment set the 3x3 environment of r to checked. If there was no red pixel in the environment you found a solution.
What you're trying to find in a more general sense is a kind of morphological filter of your array. We can define the filter as a 3x3 sliding window which sets the center of the window to the sum of the array elements within the window. Let blue squares be represented by 1 and red squares be represented by 0. In this situation, you're trying to find the closest element with a sum value of 9. Note that one way of solving this problem is slide a 3x3 window across your array so that it covers all possible locations. In this case, you would look at 9*width*height elements. You could then find the nearest sum value of 9 using a breadth-first search in, at most, width*height checks. So the naive time of your algorithm is proportional to 10*width*height You can reduce this by ensuring that your filter only has to look at one value per focal cell, rather than 9. To do so, generate a summed-area table. Now your time is proportional to 2*width*height. An example of a summed-area table You can might be able to make this faster. Each time you find a value of 9, compare it against the location of your green cell at that moment. If most cells are not 9s, this reduces your time to some proportional to width*height. Hensley et al. (2005)'s paper Fast Summed-Area Table Generation and its Applications explains how to use graphics hardware to generate the summed-area table in O(log n) time. So it's possible to really reduce run-times on this. Nehab et al. (2011)'s paper GPU-efficient recursive filtering and summed-area tables might also be useful (source code): their work suggests that for small windows, such as yours, the direct approach may be most efficient.
I think the easiest way is to use a slightly modified breadth-first search. If we talk about Manhattan distance, then each square will have maximum 4 neighbors. On each step we check if the number of neighbors is equal to 3 (the fourth neighbor is a square we came from). If so, we check diagonals. Else - continue search. public class Field3x3 { private static class Point { int x, y, distance; Point previous; public Point(int x, int y) { this.x = x; this.y = y; this.distance = 0; this.previous = this; } public Point(int x, int y, Point previous) { this.x = x; this.y = y; this.previous = previous; this.distance = previous.distance + 1; } #Override public String toString() { return "{x: " + x +", y: " + y + ", distance:" + distance +'}'; } } private static Point traverse(int[][] field, int x, int y) { int i = 0; Queue<Point> q = new LinkedList<>(); q.add(new Point(x, y)); while (!q.isEmpty()) { Point p = q.remove(); System.out.print(i++ + ". current: " + p); if (field[p.y][p.x] == 1) { field[p.y][p.x] = 2; List<Point> neighbors = getNeighbors(p, field); System.out.println(", neighbors: " + neighbors); if (neighbors.size() == 3 && checkDiagonals(p, field)) return p; for (Point neighbor : neighbors) { if (field[neighbor.y][neighbor.x] == 1) { q.add(neighbor); } } } else System.out.println(", already visited"); } return null; } private static boolean checkDiagonals(Point p, int[][] field) { return field[p.y - 1][p.x - 1] > 0 && field[p.y + 1][p.x - 1] > 0 && field[p.y - 1][p.x + 1] > 0 && field[p.y + 1][p.x + 1] > 0; } private static List<Point> getNeighbors(Point p, int[][] field) { List<Point> neighbors = new ArrayList<>(); if (p.y > 0 && field[p.y - 1][p.x] > 0 && p.y <= p.previous.y) neighbors.add(new Point(p.x, p.y - 1, p)); if (p.y < field.length - 1 && field[p.y + 1][p.x] > 0 && p.y >= p.previous.y) neighbors.add(new Point(p.x, p.y + 1, p)); if (p.x > 0 && field[p.y][p.x - 1] > 0 && p.x <= p.previous.x) neighbors.add(new Point(p.x - 1, p.y, p)); if (p.x < field[p.y].length - 1 && field[p.y][p.x + 1] > 0 && p.x >= p.previous.x) neighbors.add(new Point(p.x + 1, p.y, p)); return neighbors; } public static void main(String[] args){ int[][] field = {{1,0,0,1,1,0,1,1,1}, {1,1,1,1,1,1,1,0,1}, {1,1,1,0,1,0,1,1,1}, {0,1,1,1,1,1,1,1,0}, {1,1,1,0,0,1,1,1,0}, {1,0,1,1,1,1,0,1,0}, {1,1,1,1,0,1,1,1,0}, {1,1,1,0,1,1,1,1,0}, {1,1,1,1,0,1,1,1,0}}; System.out.println("Answer: " + traverse(field, 1, 2)); } }
Minimum number with 0 and 1 divisible by n [duplicate]
Every positive integer divide some number whose representation (base 10) contains only zeroes and ones. One can prove that: Consider the numbers 1, 11, 111, 1111, etc. up to 111... 1, where the last number has n+1 digits. Call these numbers m1, m2, ... , mn+1. Each has a remainder when divided by n, and two of these remainders must be the same. Because there are n+1 of them but only n values a remainder can take. This is an application of the famous and useful “pigeonhole principle”; Suppose the two numbers with the same remainder are mi and mj , with i < j. Now subtract the smaller from the larger. The resulting number, mi−mj, consisting of j - i ones followed by i zeroes, must be a multiple of n. But how to find the smallest answer? and effciently?
The question equals to using 10i mod n (for each i, it can be used at most once) to get a sum m of n. It's like a knapsack problem or subset sum problem. In this way, dynamic programming will do the task. In dynamic programming the complexity is O(k*n). k is the number of digits in answer. For n<105, this code works perfectly. Code: #include <stdio.h> #define NUM 2000 int main(int argc, char* argv[]) { signed long pow[NUM],val[NUM],x,num,ten; int i,j,count; for(num=2; num<NUM; num++) { for(i=0; i<NUM; pow[i++]=0); count=0; for(ten=1,x=1; x<NUM; x++) { val[x]=ten; for(j=0; j<NUM; j++)if(pow[j]&&!pow[(j+ten)%num]&&pow[j]!=x)pow[(j+ten)%num]=x; if(!pow[ten])pow[ten]=x; ten=(10*ten)%num; if(pow[0])break; } x=num; printf("%ld\tdivides\t",x=num); if(pow[0]) { while(x) { while(--count>pow[x%num]-1)printf("0"); count=pow[x%num]-1; printf("1"); x=(num+x-val[pow[x%num]])%num; } while(count-->0)printf("0"); } printf("\n"); } } PS: This sequence in OEIS.
Nice question. I use BFS to solve this question with meet-in-the-middle and some other prunings. Now my code can solve n<109 in a reasonable time. #include <cstdio> #include <cstring> class BIT { private: int x[40000000]; public: void clear() {memset(x, 0, sizeof(x));} void setz(int p, int z) {x[p>>5]=z?(x[p>>5]|(1<<(p&31))):(x[p>>5]&~(1<<(p&31)));} int bit(int p) {return x[p>>5]>>(p&31)&1;} } bp, bq; class UNIT { private: int x[3]; public: int len, sum; void setz(int z) {x[len>>5]=z?(x[len>>5]|(1<<(len&31))):(x[len>>5]&~(1<<(len&31)));} int bit(int p) {return x[p>>5]>>(p&31)&1;} } u; class MYQUEUE { private: UNIT x[5000000]; int h, t; public: void clear() {h = t = 0;} bool empty() {return h == t;} UNIT front() {return x[h];} void pop() {h = (h + 1) % 5000000;} void push(UNIT tp) {x[t] = tp; t = (t + 1) % 5000000;} } p, q; int n, md[100]; void bfs() { for (int i = 0, tp = 1; i < 200; i++) tp = 10LL * (md[i] = tp) % n; u.len = -1; u.sum = 0; q.clear(); q.push(u); bq.clear(); while (1) { u = q.front(); if (u.len >= 40) break; q.pop(); u.len++; u.setz(0); q.push(u); u.setz(1); u.sum = (u.sum + md[u.len]) % n; if (!bq.bit(u.sum)) {bq.setz(u.sum, 1); q.push(u);} if (!u.sum) { for (int k = u.len; k >= 0; k--) printf("%d", u.bit(k)); puts(""); return; } } u.len = 40; u.sum = 0; p.clear(); p.push(u); bp.clear(); while (1) { u = p.front(); p.pop(); u.len++; u.setz(0); p.push(u); u.setz(1); u.sum = (u.sum + md[u.len]) % n; if (!bp.bit(u.sum)) {bp.setz(u.sum, 1); p.push(u);} int bf = (n - u.sum) % n; if (bq.bit(bf)) { for (int k = u.len; k > 40; k--) printf("%d", u.bit(k)); while (!q.empty()) { u = q.front(); if (u.sum == bf) break; q.pop(); } for (int k = 40; k >= 0; k--) printf("%d", u.bit(k)); puts(""); return; } } } int main(void) { // 0 < n < 10^9 while (~scanf("%d", &n)) bfs(); return 0; }
There's an O(n)-time (arithmetic operations mod n, really) solution, which is more efficient than the answer currently accepted. The idea is to construct a graph on vertices 0..n-1 where vertex i has connections to (i*10)%n and (i*10+1)%n, then use breadth-first search to find the lexicographically least path from 1 to 0. def smallest(n): parents = {} queue = [(1 % n, 1, None)] i = 0 while i < len(queue): residue, digit, parent = queue[i] i += 1 if residue in parents: continue if residue == 0: answer = [] while True: answer.append(str(digit)) if parent is None: answer.reverse() return ''.join(answer) digit, parent = parents[parent] parents[residue] = (digit, parent) for digit in (0, 1): queue.append(((residue * 10 + digit) % n, digit, residue)) return None
Here is a readable solution using BFS in java. The approach is similar to David's with some improvements. You build a decision tree of whether to append a 0 or 1 and perform BFS to find the lowest such valid multiple of the input number. This solution also leverages modulo (of the input number) to compute really large results. Full description available in the comments in the code. You can also access the same code snippet in ideone. import java.util.ArrayDeque; import java.util.Arrays; import java.util.HashSet; import java.util.Queue; import java.util.Scanner; import java.util.Set; public class Main { // Return the smallest multiple of the number (as a string) consisting only of digits 0 and 1 // // All possible digits that can be constructed using the digits 0/1 can be represented // as a tree, where at each level, appending a 0 is one branch and appending a 1 is another // // If we perform BFS on this tree, the first number we see which is an exact multiple of the input // number will be the result (since it will be the smallest). Make sure to consider left // branch (i.e. 0) before considering the right branch (i.e. 1) // // The 2 paths we take at each level when the current number is num: // (num * 10) // (num * 10) + 1 // // Since the result can grow huge quite easily, it might not be possible to store the result in a // 32 or even a 64 bit int/long variable. // // One alternative is to use BigNumber, but a simpler alternative exists if we leverage modulo. // // The operations we perform above (i.e. multiplications and additions) will retain the useful part // of the result when using modulo. We use the given number itself as the modulo, and when we see a // result of 0, it means we have found a number which is an exact multiple of the input number. // // To reconstruct the number, we need to store the parent nodes of each node, when adding the node // in the queue (similar to using BFS for computing shortest path) // // We will also need to know if we appended a 0 or a 1 at each step, and so we add this information // as part of the node data structure as well. // // Re-visiting nodes is unecessary since we have seen this modulo result (i.e. value % num) already. // Any additional digits we add from now will only make the number longer and we already are tracking // the path for this same modulo result we've seen earlier. // public static String multiple(int num) { if (num < 0) { throw new IllegalArgumentException("Invalid args"); } String result = "0"; if (num > 0) { // An array to mark all the visited nodes boolean[] isVisited = new boolean[num]; Arrays.fill(isVisited, false); // The queue used by BFS Queue<Node> queue = new ArrayDeque<>(); // Add the first number 1 and mark it visited queue.add(new Node(true, 1 % num, null)); isVisited[1 % num] = true; // The final destination node which represents the answer Node destNode = null; while (!queue.isEmpty()) { // Get the next node from the queue Node currNode = queue.remove(); if (currNode.val == 0) { // We have reached a valid multiple of num destNode = currNode; break; } else { // Visit the next 2 neighbors // Append 0 - (currNode.val * 10) // Append 1 - (currNode.val * 10) + 1 // Append a '0' int val1 = (currNode.val * 10) % num; if (!isVisited[val1]) { queue.add(new Node(false, val1, currNode)); isVisited[val1] = true; } // Append a '1' int val2 = (val1 + 1) % num; if (!isVisited[val2]) { queue.add(new Node(true, val2, currNode)); isVisited[val2] = true; } } } // Trace the path from destination to source if (destNode == null) { throw new IllegalStateException("Result should not be null"); } else { StringBuilder reverseResultBuilder = new StringBuilder(); Node currNode = destNode; while (currNode != null) { reverseResultBuilder.append(currNode.isDigitOne ? '1' : '0'); currNode = currNode.parent; } result = reverseResultBuilder.reverse().toString(); } } return result; } // Node represents every digit being appended in the decision tree private static class Node { // True if '1', false otherwise (i.e. '0') public final boolean isDigitOne; // The number represented in the tree modulo the input number public final int val; // The parent node in the tree public final Node parent; public Node(boolean isDigitOne, int val, Node parent) { this.isDigitOne = isDigitOne; this.val = val; this.parent = parent; } } public static void main(String[] args) { int num = new Scanner(System.in).nextInt(); System.out.println("Input number: " + num); System.out.println("Smallest multiple using only 0s and 1s as digits: " + Main.multiple(num)); } }
I think this is a fair and interesting question. Please note that though what you describe is a proof there always exist such number, the found number will not always be minimal. Only solution I can think of is to compute the remainders of the powers of 10 modulus the given n and than try to construct a sum giving remainder 0 modulo n using at most one of each of these powers. You will never need more than n different powers(which you prove i your question).
This is a fast way to get the first 792 answers. Def the most simple code: __author__ = 'robert' from itertools import product def get_nums(max_length): assert max_length < 21 #Otherwise there will be over 2 million possibilities for length in range(1, max_length + 1): for prod in product("10", repeat=length): if prod[0] == '1': yield int("".join(prod)) print list(get_nums(4)) [1, 11, 10, 111, 110, 101, 100, 1111, 1110, 1101, 1100, 1011, 1010, 1001, 1000] nums = sorted(get_nums(20)) print len(nums) solution = {} operations = 0 for factor in range(1, 1000): for num in nums: operations += 1 if num % factor == 0: solution[factor] = num break print factor, operations if factor not in solution: print "no solution for factor %s" % factor break print solution[787] max_v = max(solution.values()) for factor, val in solution.items(): if val == max_v: print factor, max_v [1, 11, 10, 111, 110, 101, 100, 1111, 1110, 1101, 1100, 1011, 1010, 1001, 1000] 1048575 1 1 2 3 3 10 4 14 5 16 6 30 7 39 8 47 9 558 10 560 11 563 12 591 13 600 14 618 15 632 16 648 17 677 18 1699 19 1724 20 1728 .. .. 187 319781 188 319857 .. .. 791 4899691 792 5948266 no solution for factor 792 10110001111 396 11111111111111111100
Here is a C# solution using linked list using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Collections; namespace ConsoleApplication1 { class Program { public static void print(LinkedList<int> lst) { foreach(int i in lst) { Console.Write(i); } } static void Main(string[] args) { int number = Convert.ToInt32(Console.ReadLine()); int product; LinkedList<int> list = new LinkedList<int>(); bool Istrue = true; int range = 1; while (range <= 10) { Istrue = true; product = number * range; while (product > 0) { list.AddFirst(product % 10); product /= 10; } foreach (int i in list) { if (i > 1) Istrue = false; } if (Istrue) { print(list); break; } else { list.Clear(); } range++; } Console.WriteLine("Done"); string s = Console.ReadLine(); } } }
My algorithm will be :- 1)Construct the sorted tree of of n possible numbers(say n initially is 10). So in this example it will contain 1,10,11,100,101,110,111.... 2)Then loop over the list and perform on each no x%GivenNo, if its o its smallest possible no 3)Otherwise repeat step 3 with another 10 numbers
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication2 { class Class1 { public static void Main() { List<string> possibleCombination = new List<string>(); for (int i = 2; i < 10000; i++) { possibleCombination.Add(Convert.ToString(i, 2)); } var input = Console.ReadLine(); long output = 0; foreach (var item in possibleCombination) { if (Convert.ToInt64(item) % Convert.ToInt64(i) == 0) { output = Convert.ToInt64(item); break; } } Console.WriteLine(output); Console.ReadLine(); } } }
Here is complete c# code in O(n) using graph and bfs approach. using System; using System.Collections.Generic; using System.Collections; using System.Security.Cryptography; using System.Linq; using System.Runtime.InteropServices; class Solution { public class Edge : IComparable { public int From { get; set; } public int To { get; set; } public int Weight { get; set; } public bool IsDirected { get; set; } public Edge(int from, int to, bool isDirected = false, int weight = 0) { this.From = from; this.To = to; this.Weight = weight; this.IsDirected = isDirected; } public int CompareTo(object obj) { if (obj is Edge) { var comparingTo = obj as Edge; return this.Weight.CompareTo(comparingTo.Weight); } return 0; //TODO:what should we return? } } public class AdjNode { public int EdgeWeight { get; set; } public int Id { get; set; } public AdjNode(int id) { this.Id = id; this.EdgeWeight = 0; } public AdjNode(int id, int weight) { this.Id = id; this.EdgeWeight = weight; } } public class GraphAdj { public int V { get; set; } public List<AdjNode>[] adj { get; set; } public List<Edge> Edges { get; set; } public GraphAdj(int v) { this.V = v; this.adj = new List<AdjNode>[this.V]; for (int i = 0; i < this.V; i++) { this.adj[i] = new List<AdjNode>(); //allocate actual memory } this.Edges = new List<Edge>(); } public void AddDirectedEdge(int from, int to) { adj[from].Add(new AdjNode(to)); this.Edges.Add(new Edge(from,to,true)); } public void AddDirectedEdge(int from, int to, int weight) { adj[from].Add(new AdjNode(to,weight)); this.Edges.Add(new Edge(from, to, true, weight)); } } public string multiple(int A) { int n = A; GraphAdj directedGraphForNumber = new GraphAdj(n); Queue<int> queueForNumbers = new Queue<int>(); string result = String.Empty; bool[] visitedForNumbers = new bool[directedGraphForNumber.V]; int[] suffixes = new int[2] { 0, 1 }; //we will start from 1st node out of n node queueForNumbers.Enqueue(1); visitedForNumbers[1] = true; while (true) { int from = queueForNumbers.Dequeue(); if (from == 0) break; for (int i = 0; i < suffixes.Length; i++) { int toNode = from * 10 + suffixes[i]; int reminder = toNode % n; if (visitedForNumbers[reminder] == false) { visitedForNumbers[reminder] = true; queueForNumbers.Enqueue(reminder); directedGraphForNumber.AddDirectedEdge(from, reminder,suffixes[i]); } } } //Do BFS traversal with edges until zero th node encounters bool[] visitedForBfs = new bool[directedGraphForNumber.V]; Queue<int> queueForBfs = new Queue<int>(); int[] parent = new int[directedGraphForNumber.V]; int source = 1; visitedForBfs[source] = true; queueForBfs.Enqueue(source); parent[source] = -1; while (queueForBfs.Count > 0) { int currentVertex = queueForBfs.Dequeue(); foreach (var adjacentVertex in directedGraphForNumber.adj[currentVertex]) { if (visitedForBfs[adjacentVertex.Id] == false) { queueForBfs.Enqueue(adjacentVertex.Id); parent[adjacentVertex.Id] = currentVertex; visitedForBfs[adjacentVertex.Id] = true; } if (adjacentVertex.Id == 0) // we reach zero th node { queueForBfs.Clear(); //break out of bfs } } } //now time to find path all the way to start from zero using parent List<int> pathListUsingParent = new List<int>(); int current = 0; pathListUsingParent.Add(0); // add zero while (current!=1) { pathListUsingParent.Add(parent[current]); current = parent[current]; } //reverse path to make number using edges pathListUsingParent.Reverse(); result += "1"; //start node //now read edges for (int i = 0; i < pathListUsingParent.Count-1; i++) { int from = pathListUsingParent[i]; int to = pathListUsingParent[i + 1]; result += directedGraphForNumber.adj[from].FirstOrDefault(adj => adj.Id == to).EdgeWeight; } return result; } }
Here's a brute force version in Raku: say (1..Inf).map( *.base(2) ).first( * %% $n ); The code generates a lazy (potentially infinite) sequence of candidate numbers and then searches for the first element that's divisible by n. Being brute force it's not exceptionally fast, but the code is striking in its simplicity and expressiveness, as it is typical for Raku.
Construct the largest possible rectangle out of line segments of given lengths
I recently participated in a competition where I was asked this question. Given an array with lengths what is the area of the biggest rectangle that can be made using ALL the lengths. The lengths can be added but not broken in between. Example: [ 4,2,4,4,6,8 ] given this array the best we can do is make a rectangle of sides 8 and 6 like this. giving an area of 8 * 6 = 48. I am a beginner and even after a long hard think about how to do it I am unable to get anywhere. I am not looking for a solution but any clue to nudge me in the right direction would be appreciated. TIA Edit: Somebody pointed out(comment deleted now) that its difficult to explain the solution with just hints and not posting some code. Kindly post code if necessary.
The problem is NP-Hard, thus the backtracking solution [or other exponential solution as suggested by #vhallac] will be your best shot, since there is not known [and if P!=NP, there is no existing] polynomial solution for this kind of problem. NP-Hardness proof: First, we know that a rectangle consists of 4 edges, that are equal in pairs [e1=e2,e3=e4]. We will show that if there is a polynomial algorithm A to this problem, we can also solve the Partition Problem, by the following algorithm: input: a group of numbers S=a1,a2,...,an output: true if and only if the numbers can be partitioned algorithm: sum <- a1 + a2 + .. + an lengths <- a1, a2 , ... , an , (sum*5), (sum*5) activate A with lengths. if A answered there is any rectangle [solution is not 0], answer True else answer False Correctness: (1) if there is a partition to S, let it be S1,S2, there is also a rectangle with edges: (sum*5),(sum*5),S1,S2, and the algorithm will yield True. (2) if the algorithm yields True, there is a rectangle available in lengths, since a1 + a2 + ... + an < sum*5, there are 2 edges with length sum*5, since the 2 other edges must be made using all remaining lengths [as the question specified], each other edge is actually of length (a1 + a2 + ... + an)/2, and thus there is a legal partition to the problem. Conclusion: There is a reduction PARTITION<=(p) this problem, and thus, this problem is NP-Hard EDIT: the backtracking solution is pretty simple, get all possible rectangles, and check each of them to see which is the best. backtracking solution: pseudo-code: getAllRectangles(S,e1,e2,e3,e4,sol): if S == {}: if legalRectangle(e1,e2,e3,e4): sol.add((e1,e2,e3,e4)) else: //S is not empty elem <- S[0] getAllRectangles(S-elem,e1+elem,e2,e3,e4,sol) getAllRectangles(S-elem,e1,e2+elem,e3,e4,sol) getAllRectangles(S-elem,e1,e2,e3+elem,e4,sol) getAllRectangles(S-elem,e1,e2,e3,e4+elem,sol) getRectangle(S): RECS <- new Set getAllRectangles(S,{},{},{},{},RECS) getBest(RECS) EDIT2: As discussed in the comments, this answer shows not only this is hard to find the BEST rectangle, it is also hard to find ANY rectangle, making this problem hard for heuristic solutions as well.
Here is one solution to the problem in Python. It is not optimized at all. I even check 2, 4 after I check 4,2, for example. But for showing how you can find a solution, I think it is good enough. def all_but(lst, pos): return lst[0:pos]+lst[pos+1:] def find_sets_with_len(segs, l): for i in range(0, len(segs)): val = segs[i] if (val == l): yield [val], all_but(segs, i) if (val < l): for soln, rest in find_sets_with_len(all_but(segs, i), l - val): yield [val]+soln, rest def find_rect(segs, l1, l2): for side1, rest1 in find_sets_with_len(segs, l1): for side2, rest2 in find_sets_with_len(rest1, l1): for side3, rest3 in find_sets_with_len(rest2, l2): return [side1, side2, side3, rest3] def make_rect(segs): tot_len = sum(segs) if (tot_len %2) == 0: opt_len=tot_len/4 for l in range(opt_len, 0, -1): sides = find_rect(segs, l, tot_len/2-l) if sides is not None: print(sides) return sides print("Can't find any solution") make_rect([4,2,4,4,6,8]) The idea is simple: first, calculate the optimal length (that is, the length to make a square), then search everything starting off with the optimal length, and go down to 1 for one side. For each length, enumerate all sets for one side of the claculated length, then enumerate all sets for the opposite side (of the same length), then if I can find one more set of the remaining length (that is total_len/2 minus the side length I am looking at), then I've got the best solution. This happens in find_rect() function.
Well, I get little bit bored so play around with Java to have some experience, can be poorly coded and without tuning, as I am trying to increase my coding skill, comments are welcome. My computer able to answer me for small arrays:) Output looks like: Largest rectangle range is ; 48 ------------------------------------------------- input values; [ 4,2,4,4,6,8,9 ] ------------------------------------------------- Array details of the rectangle: A1: [ 6 ] B1: [ 8 ] A2: [ 2,4 ] B2: [ 4,4 ] combination.class using Kenneth algorithm; import java.math.BigInteger; public class Combination { /** * Burak */ private int[] a; private int n; private int r; private BigInteger numLeft; private BigInteger total; public Combination (int n, int r) { if (r > n) { throw new IllegalArgumentException (); } if (n < 1) { throw new IllegalArgumentException (); } this.n = n; this.r = r; a = new int[r]; BigInteger nFact = getFactorial (n); BigInteger rFact = getFactorial (r); BigInteger nminusrFact = getFactorial (n - r); total = nFact.divide (rFact.multiply (nminusrFact)); reset (); } //------ // Reset //------ public void reset () { for (int i = 0; i < a.length; i++) { a[i] = i; } numLeft = new BigInteger (total.toString ()); } //------------------------------------------------ // Return number of combinations not yet generated //------------------------------------------------ public BigInteger getNumLeft () { return numLeft; } //----------------------------- // Are there more combinations? //----------------------------- public boolean hasMore () { return numLeft.compareTo (BigInteger.ZERO) == 1; } //------------------------------------ // Return total number of combinations //------------------------------------ public BigInteger getTotal () { return total; } //------------------ // Compute factorial //------------------ private static BigInteger getFactorial (int n) { BigInteger fact = BigInteger.ONE; for (int i = n; i > 1; i--) { fact = fact.multiply (new BigInteger (Integer.toString (i))); } return fact; } //-------------------------------------------------------- // Generate next combination (algorithm from Rosen p. 286) //-------------------------------------------------------- public int[] getNext () { if (numLeft.equals (total)) { numLeft = numLeft.subtract (BigInteger.ONE); return a; } int i = r - 1; while (a[i] == n - r + i) { i--; } a[i] = a[i] + 1; for (int j = i + 1; j < r; j++) { a[j] = a[i] + j - i; } numLeft = numLeft.subtract (BigInteger.ONE); return a; } } And main Combinator.class; import java.util.*; public class Combinator { /** * #param args */ private static int[] ad; private static int[] bd; private static String a1; private static String a2; private static String b1; private static String b2; private static int bestTotal =0; public static void main(String[] args) { int[] array={4,2,4,4,6,8,9}; getBestCombination(array, 1); if(bestTotal <= 0){ System.out.println("System couldnt create any rectangle."); }else{ System.out.println("Largest rectangle range is ; " + bestTotal); System.out.println("-------------------------------------------------"); System.out.println("input values; " + parseArrayToString(array)); System.out.println("-------------------------------------------------"); System.out.println("Array details of the rectangle:"); System.out.println("A1: " + a1); System.out.println("B1: " + b1); System.out.println("A2: " + a2); System.out.println("B2: " + b2); } } private static void getBestCombination(int[] array, int level){ int[] a; int[] b; int bestPerimeter = getTotal(array,true); Vector<Vector<Integer>> results = null; for(int o=array.length-1;o>=1;o--){ for(int u=bestPerimeter;u>=1;u--){ results = Combinator.compute (array, o, u); if(results.size() > 0){ for(int i=0;i<results.size();i++){ a = new int[results.elementAt(i).size()]; for(int j = 0;j<results.elementAt(i).size();j++){ a[j] = results.elementAt(i).elementAt(j); } b = removeItems(array, results.elementAt(i)); if(level == 1){ getBestCombination(a,2); getBestCombination(b,3); }else if(level == 2){ ad = a; bd = b; }else{ getBestCombination(a,4); getBestCombination(b,4); if(getTotal(ad, false) == getTotal(a, false) && getTotal(bd, false) == getTotal(b, false)){ if(bestTotal<(getTotal(ad, false)*getTotal(bd, false))){ bestTotal = getTotal(ad, false)*getTotal(bd, false); a1 = parseArrayToString(ad); a2 = parseArrayToString(a); b1 = parseArrayToString(bd); b2 = parseArrayToString(b); } }else if(getTotal(ad, false) == getTotal(b, false) && getTotal(bd, false) == getTotal(a, false)){ if(bestTotal<(getTotal(ad, false)*getTotal(bd, false))){ bestTotal = getTotal(ad, false)*getTotal(bd, false); a1 = parseArrayToString(ad); a2 = parseArrayToString(b); b1 = parseArrayToString(bd); b2 = parseArrayToString(a); } } } } } } } } private static String parseArrayToString(int[] items){ String s = "[ "; for(int i=0;i<items.length;i++){ if(i!=items.length-1){ s = s + items[i] + ","; }else{ s = s + items[i]; } } s = s + " ]"; return s; } #SuppressWarnings("rawtypes") private static int[] removeItems(int[] array, Vector items){ ArrayList<Integer> res = new ArrayList<Integer>(); for(int i=0;i<array.length;i++){ res.add(array[i]); } for(int u = 0;u<items.size();u++){ res.remove(items.elementAt(u)); } int[] results = new int[res.size()]; for(int o=0;o<res.size();o++){ results[o] = res.get(o); } return results; } private static int getTotal(int[] array,boolean bestPerimeter){ int sum = 0; for (int i = 0; i < array.length; i++) { sum += array[i]; } if(bestPerimeter == true){ if(sum%2!=0){ sum = sum -1; } sum = sum/2; } //System.out.println(sum); return sum; } #SuppressWarnings("rawtypes") private static int getSum (Vector v) { int sum = 0; Integer n; for (int i = 0; i < v.size (); i++) { n = (Integer) v.elementAt(i); sum += n.intValue (); } return sum; } #SuppressWarnings({ "rawtypes", "unchecked" }) public static Vector<Vector<Integer>> compute (int[] array, int atATime, int desiredTotal) { int[] indices; Combination gen = new Combination (array.length, atATime); Vector results = new Vector (); Vector combination; int sum; Integer intObj; while (gen.hasMore ()) { combination = new Vector (); indices = gen.getNext (); for (int i = 0; i < indices.length; i++) { intObj = new Integer (array[indices[i]]); combination.addElement (intObj); } sum = getSum (combination); if (sum == desiredTotal) { Collections.sort (combination); if (!results.contains (combination)) { results.addElement (combination); } } } return results; } }
Help with algorithm problem from SPOJ
I thought it would be a fun problem: Prime Path But...It is hard for me. My only idea is "To do something with knapsack problem".. and no other ideas. Could You track me for good way? It's not for any challenge or University homework. I just want to learn something. _ Ok, but firstly, how to find this prime numbers? Do i need to find all 4digit prime numbers, add it to graph? For now i have generating all prime numbers. http://pastebin.com/wbhRNRHQ Could You give me sample code to declare graph build on neighbour list?
Seems like a straightforward graph path finding problem. Take all 4 digit primes as the vertices. Connect two with an edge, if we can go from one to the other. Now given two, you need to find the shortest path between them, in the graph we just formed. A simple BFS (breadth-first-search) should do for that. For programming contests with time limits, you could even hardcode every possible prime pair path and get close to zero running time!
Build a graph where the nodes are all the 4 digit prime numbers, and there are arcs everywhere two numbers have three digits in common. From there, it's a basic graph traversal to find the lowest-cost path from one node to another.
I came across a similar question where I had to convert one 4 digit prime number 1033 to another 4 digit prime number 3739 in minimum number of steps. I was able to solve the problem, it might not be efficient but here is the working code for the same. Below code has been written in Java import java.util.*; public class PrimeNumberProblem { public static void main(String... args) { System.out.println("Minimum number of steps required for converting 1033 to 3739 are = " + getMinSteps(1033, 3739)); } public static int getMinSteps(int a, int b) { if (a == b) return 0; List<Integer> primes = new ArrayList<>(); // get all the 4 digit prime numbers primes = getPrimeNumbers(); // consists of graph with vertices as all the prime numbers Graph graph = addNumbersToGraph(primes); // adding edges to the graph vertices Graph finalGraph = addWeightToGraph(graph); // min number of steps required int result = findShortestRoute(finalGraph.getVertex(a), finalGraph.getVertex(b)); return result; } private static int findShortestRoute(Vertex source, Vertex dest) { if (source.getVertexValue() == dest.getVertexValue()) return 0; // step 1 Initialize the queue. Also Map to store path Queue<Vertex> visitedQueue = new LinkedList<>(); Map<Vertex, Vertex> currentPrevMap = new HashMap<Vertex, Vertex>(); // step 2 start from visiting S (starting node), and mark it visited, add to queue Map<Integer, Boolean> visited = new HashMap<Integer, Boolean>(); visited.put(source.getVertexValue(), true); visitedQueue.add(source); int level = 0; // step 3 Repeat until queue is empty while (!visitedQueue.isEmpty()) { // step 4 remove from queue Vertex current = visitedQueue.remove(); if (current.getVertexValue() == dest.getVertexValue()) { printPath(source, dest, currentPrevMap); return level; } else if (current.getAdjacentVertices().size() > 0) { level++; } // step 5 add each of the unvisited neighbour and mark visited for (Vertex adjacentVertex : current.getAdjacentVertices()) { Integer value = adjacentVertex.getVertexValue(); if (value == dest.getVertexValue()) { currentPrevMap.put(adjacentVertex, current); printPath(source, dest, currentPrevMap); return level; } if (visited.get(value) == null) { currentPrevMap.put(adjacentVertex, current); // mark visited and enqueue it visited.put(value, true); visitedQueue.add(adjacentVertex); } } } // not found System.out.println("Dest vertex not found"); return -1; } private static void printPath(Vertex source, Vertex dest, Map<Vertex, Vertex> currentPrevMap) { Vertex node = dest; System.out.println("Reverse Path from source: " + source.getVertexValue() + " to dest: " + dest.getVertexValue()); while (node != source) { System.out.println(node.getVertexValue()); node = currentPrevMap.get(node); } System.out.println(source.getVertexValue()); } private static Graph addWeightToGraph(Graph graph) { List<Vertex> vertices = graph.getAllVertices(); for (Vertex i : vertices) { for (Vertex j : vertices) { if (i.equals(j)) continue; if (distance(i, j) == 1) { i.getAdjacentVertices().add(j); // i.addEdge(new Edge(i, j, 1)); } } } return graph; } private static int distance(Vertex source, Vertex dest) { if (source.getVertexValue() == dest.getVertexValue()) { return 0; } char[] numA = extractIntegers(source.getVertexValue()); char[] numB = extractIntegers(dest.getVertexValue()); int len1 = numA.length; int tracker = 0; for (int i = 0; i < len1; i++) { if (numA[i] != numB[i]) { numA[i] = numB[i]; tracker++; String sA = String.copyValueOf(numA); String sB = String.copyValueOf(numB); // if we have reached destination if (Integer.parseInt(sA) == Integer.parseInt(sB)) { return tracker; } } } return tracker; } private static char[] extractIntegers(int i) { char[] arr = Integer.toString(i).toCharArray(); return arr; } private static Graph addNumbersToGraph(List<Integer> primes) { Graph g = new Graph(); for (Integer prime : primes) { g.addVertex(new Vertex(prime)); } return g; } private static List<Integer> getPrimeNumbers() { List<Integer> fourDigitPrimes = new ArrayList<>(); fourDigitPrimes.add(1033); fourDigitPrimes.add(1733); fourDigitPrimes.add(3733); fourDigitPrimes.add(3739); // for (int i = 1000; i < 9999; i++) { // if (isPrime(i)) // fourDigitPrimes.add(i); // } return fourDigitPrimes; } private static boolean isPrime(int i) { for (int k = 2; k < Math.sqrt(i); k++) { if (i % k == 0) return false; } return true; } } class Graph { public List<Vertex> vertexList = new ArrayList<Vertex>(); public void addVertex(Vertex V) { vertexList.add(V); } public List getAllAdjacentNodes(Vertex V) { return V.getAdjacentVertices(); } public List getAllVertices() { return vertexList; } public Vertex getVertex(int val) { Iterator<Vertex> keys = vertexList.iterator(); while (keys.hasNext()) { Vertex v = keys.next(); if (v.getVertexValue() == val) return v; } return null; } } class Vertex { int value; private List<Vertex> adjacentVertices = new ArrayList<Vertex>(); public Vertex(int v) { this.value = v; } public List<Vertex> getAdjacentVertices() { return adjacentVertices; } public int getVertexValue() { return value; } #Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Vertex vertex = (Vertex) o; return value == vertex.value; } #Override public int hashCode() { return value; } }
Look into "breadth-first search". Also worth bearing in mind here that the problem can be approached "from both ends" simultaneously (a chain from numbers X to Y can be reversed to get Y to X, and you can exploit this). Precalculating primes will avoid much computation along the way.
I'd run a BFS using probable prime testing, which would work relatively well with only 4 digit numbers. With only 4 digits, also, you may want to use more exacting methods to produce all primes to compare against for faster prime checking.
Could You give me sample code to declare graph build on neighbour list? here is a sample code for breadth first search public static final int MAX = 10000; boolean[] prime = new boolean[MAX]; int[] dist = new int[MAX]; //get digit i [1 to 4] in num public int getDigit(int num,int i){ return num % ((int)Math.pow(10, i)) / ((int) Math.pow(10, i-1)); } //set digit i to d public int setDigit(int num,int i,int d){ return (num - getDigit(num, i)*(int)Math.pow(10, i-1)) + d * (int)Math.pow(10,i-1); } public int bfs(int start,int end){ Queue<Integer> q = new LinkedList<Integer>(); q.add(start); HashSet<Integer> visited = new HashSet<Integer>(); visited.add(start); dist[start] = 0; int x,y,d = 0; while (q.size() > 0){ x = q.poll(); d = dist[x]; if (x == end) return d; for (int i = 1; i < 5; i++) { //digit number i for (int j = 0; j < 10; j++) { //avoid setting last digit if (j == 0 && i == 4) continue; //set digit number i to j y = setDigit(x, i, j); if (prime[y] && y != x && !visited.contains(y)){ q.add(y); visited.add(y); dist[y] = d + 1; } } } } return -1; }
Here is my solution using BFS and I have already saved all 4 digit prime numbers into an array as there is no need to write a function to calculate the prime numbers. I hope it helps #include<stdio.h> int hash[10000]; int a,b,ans,level,new_num,count; int prime[] = {1009,1013,1019,1021,1031,1033,1039,1049,1051,1061,1063,1069,1087,1091,1093,1097,1103,1109,1117,1123,1129,1151,1153,1163,1171,1181,1187,1193,1201,1213,1217,1223,1229,1231,1237,1249,1259,1277,1279,1283,1289,1291,1297,1301,1303,1307,1319,1321,1327,1361,1367,1373,1381,1399,1409,1423,1427,1429,1433,1439,1447,1451,1453,1459,1471,1481,1483,1487,1489,1493,1499,1511,1523,1531,1543,1549,1553,1559,1567,1571,1579,1583,1597,1601,1607,1609,1613,1619,1621,1627,1637,1657,1663,1667,1669,1693,1697,1699,1709,1721,1723,1733,1741,1747,1753,1759,1777,1783,1787,1789,1801,1811,1823,1831,1847,1861,1867,1871,1873,1877,1879,1889,1901,1907,1913,1931,1933,1949,1951,1973,1979,1987,1993,1997,1999,2003,2011,2017,2027,2029,2039,2053,2063,2069,2081,2083,2087,2089,2099,2111,2113,2129,2131,2137,2141,2143,2153,2161,2179,2203,2207,2213,2221,2237,2239,2243,2251,2267,2269,2273,2281,2287,2293,2297,2309,2311,2333,2339,2341,2347,2351,2357,2371,2377,2381,2383,2389,2393,2399,2411,2417,2423,2437,2441,2447,2459,2467,2473,2477,2503,2521,2531,2539,2543,2549,2551,2557,2579,2591,2593,2609,2617,2621,2633,2647,2657,2659,2663,2671,2677,2683,2687,2689,2693,2699,2707,2711,2713,2719,2729,2731,2741,2749,2753,2767,2777,2789,2791,2797,2801,2803,2819,2833,2837,2843,2851,2857,2861,2879,2887,2897,2903,2909,2917,2927,2939,2953,2957,2963,2969,2971,2999,3001,3011,3019,3023,3037,3041,3049,3061,3067,3079,3083,3089,3109,3119,3121,3137,3163,3167,3169,3181,3187,3191,3203,3209,3217,3221,3229,3251,3253,3257,3259,3271,3299,3301,3307,3313,3319,3323,3329,3331,3343,3347,3359,3361,3371,3373,3389,3391,3407,3413,3433,3449,3457,3461,3463,3467,3469,3491,3499,3511,3517,3527,3529,3533,3539,3541,3547,3557,3559,3571,3581,3583,3593,3607,3613,3617,3623,3631,3637,3643,3659,3671,3673,3677,3691,3697,3701,3709,3719,3727,3733,3739,3761,3767,3769,3779,3793,3797,3803,3821,3823,3833,3847,3851,3853,3863,3877,3881,3889,3907,3911,3917,3919,3923,3929,3931,3943,3947,3967,3989,4001,4003,4007,4013,4019,4021,4027,4049,4051,4057,4073,4079,4091,4093,4099,4111,4127,4129,4133,4139,4153,4157,4159,4177,4201,4211,4217,4219,4229,4231,4241,4243,4253,4259,4261,4271,4273,4283,4289,4297,4327,4337,4339,4349,4357,4363,4373,4391,4397,4409,4421,4423,4441,4447,4451,4457,4463,4481,4483,4493,4507,4513,4517,4519,4523,4547,4549,4561,4567,4583,4591,4597,4603,4621,4637,4639,4643,4649,4651,4657,4663,4673,4679,4691,4703,4721,4723,4729,4733,4751,4759,4783,4787,4789,4793,4799,4801,4813,4817,4831,4861,4871,4877,4889,4903,4909,4919,4931,4933,4937,4943,4951,4957,4967,4969,4973,4987,4993,4999,5003,5009,5011,5021,5023,5039,5051,5059,5077,5081,5087,5099,5101,5107,5113,5119,5147,5153,5167,5171,5179,5189,5197,5209,5227,5231,5233,5237,5261,5273,5279,5281,5297,5303,5309,5323,5333,5347,5351,5381,5387,5393,5399,5407,5413,5417,5419,5431,5437,5441,5443,5449,5471,5477,5479,5483,5501,5503,5507,5519,5521,5527,5531,5557,5563,5569,5573,5581,5591,5623,5639,5641,5647,5651,5653,5657,5659,5669,5683,5689,5693,5701,5711,5717,5737,5741,5743,5749,5779,5783,5791,5801,5807,5813,5821,5827,5839,5843,5849,5851,5857,5861,5867,5869,5879,5881,5897,5903,5923,5927,5939,5953,5981,5987,6007,6011,6029,6037,6043,6047,6053,6067,6073,6079,6089,6091,6101,6113,6121,6131,6133,6143,6151,6163,6173,6197,6199,6203,6211,6217,6221,6229,6247,6257,6263,6269,6271,6277,6287,6299,6301,6311,6317,6323,6329,6337,6343,6353,6359,6361,6367,6373,6379,6389,6397,6421,6427,6449,6451,6469,6473,6481,6491,6521,6529,6547,6551,6553,6563,6569,6571,6577,6581,6599,6607,6619,6637,6653,6659,6661,6673,6679,6689,6691,6701,6703,6709,6719,6733,6737,6761,6763,6779,6781,6791,6793,6803,6823,6827,6829,6833,6841,6857,6863,6869,6871,6883,6899,6907,6911,6917,6947,6949,6959,6961,6967,6971,6977,6983,6991,6997,7001,7013,7019,7027,7039,7043,7057,7069,7079,7103,7109,7121,7127,7129,7151,7159,7177,7187,7193,7207,7211,7213,7219,7229,7237,7243,7247,7253,7283,7297,7307,7309,7321,7331,7333,7349,7351,7369,7393,7411,7417,7433,7451,7457,7459,7477,7481,7487,7489,7499,7507,7517,7523,7529,7537,7541,7547,7549,7559,7561,7573,7577,7583,7589,7591,7603,7607,7621,7639,7643,7649,7669,7673,7681,7687,7691,7699,7703,7717,7723,7727,7741,7753,7757,7759,7789,7793,7817,7823,7829,7841,7853,7867,7873,7877,7879,7883,7901,7907,7919,7927,7933,7937,7949,7951,7963,7993,8009,8011,8017,8039,8053,8059,8069,8081,8087,8089,8093,8101,8111,8117,8123,8147,8161,8167,8171,8179,8191,8209,8219,8221,8231,8233,8237,8243,8263,8269,8273,8287,8291,8293,8297,8311,8317,8329,8353,8363,8369,8377,8387,8389,8419,8423,8429,8431,8443,8447,8461,8467,8501,8513,8521,8527,8537,8539,8543,8563,8573,8581,8597,8599,8609,8623,8627,8629,8641,8647,8663,8669,8677,8681,8689,8693,8699,8707,8713,8719,8731,8737,8741,8747,8753,8761,8779,8783,8803,8807,8819,8821,8831,8837,8839,8849,8861,8863,8867,8887,8893,8923,8929,8933,8941,8951,8963,8969,8971,8999,9001,9007,9011,9013,9029,9041,9043,9049,9059,9067,9091,9103,9109,9127,9133,9137,9151,9157,9161,9173,9181,9187,9199,9203,9209,9221,9227,9239,9241,9257,9277,9281,9283,9293,9311,9319,9323,9337,9341,9343,9349,9371,9377,9391,9397,9403,9413,9419,9421,9431,9433,9437,9439,9461,9463,9467,9473,9479,9491,9497,9511,9521,9533,9539,9547,9551,9587,9601,9613,9619,9623,9629,9631,9643,9649,9661,9677,9679,9689,9697,9719,9721,9733,9739,9743,9749,9767,9769,9781,9787,9791,9803,9811,9817,9829,9833,9839,9851,9857,9859,9871,9883,9887,9901,9907,9923,9929,9931,9941,9949,9967,9973}; int size = sizeof(prime)/sizeof(prime[0]); int bfs(int,int); typedef struct q{ int x, c; } queue; queue qq[10000]; int isprime(int x) { int l,r,m; l=m=0; r=size-1; while (l <= r) { int m = l + (r-l)/2; if (prime[m] == x) return 1; if (prime[m] < x) l = m + 1; else r = m - 1; } return 0; } int bfs(int num1,int num2) { int i,j,k,p,q,n; new_num=p=q=0; i=0; j=1; qq[i].x = num1; qq[i].c = 0; hash[num1] = 1; while(i!=j) { n = qq[i].x; level = qq[i].c; if(n==num2) { count = level; return count; } level++; p = n%1000; for(k=1;k<10;k++) { new_num = (k*1000)+ p; if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num])) { hash[new_num] = 1; qq[j].x = new_num; qq[j].c = level; j++; }} p=q=new_num=0; p = n/1000; q = n%100; for(k=0;k<10;k++) { new_num = (p*1000)+k*100+q; if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num])) { hash[new_num] = 1; qq[j].x = new_num; qq[j].c = level; j++; }} p=q=new_num=0; p = n/100; q = n%10; for(k=0;k<10;k++) { new_num = (p*100)+k*10+q; if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num])) { hash[new_num] = 1; qq[j].x = new_num; qq[j].c = level; j++; }} p=q=new_num=0; p = n/10; for(k=0;k<10;k++) { new_num = (p*10)+k; if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num])) { hash[new_num] = 1; qq[j].x = new_num; qq[j].c = level; j++; }} p=q=new_num=0; i++; } return -1;} int main() { int v,tc; setbuf(stdout,NULL); scanf("%d",&tc); for(v=1;v<=tc;v++) { int i,j; a=b=ans=level=new_num=count=0; for(i=0;i<10000;i++) {qq[i].x=0; qq[i].c=0; hash[i]=0;} scanf("%d%d",&a,&b); if(a==b) { ans = 0;} else { ans = bfs(a,b);} printf("Case #%d\n", v); if(ans==-1) { printf("Impossible\n"); } else {printf("%d\n",ans);} } return 0; }
My Python solution using BFS: import queue # Class to represent a graph class Graph: def __init__(self, V): self.V = V # No. of vertices self.prime_list = [[] for i in range(V)] # function to add an edge to graph def addedge(self, V1, V2): self.prime_list[V1].append(V2) self.prime_list[V2].append(V1) def bfs(self, in1, in2): visited = [0] * self.V que = queue.Queue() visited[in1] = 1 que.put(in1) while not que.empty(): prime_index = que.get() i = 0 while i < len(self.prime_list[prime_index]): if not visited[self.prime_list[prime_index][i]]: visited[self.prime_list[prime_index][i]] = visited[prime_index] + 1 que.put(self.prime_list[prime_index][i]) if self.prime_list[prime_index][i] == in2: return visited[self.prime_list[prime_index][i]] - 1 i += 1 # // Finding all 4 digit prime numbers def SieveOfEratosthenes(v): # Create a boolean array "prime[0..n]" and initialize all entries it as true. A value in prime[i] will be # finally be false if i is Not a prime, else true. n = 9999 prime = [True] * (n + 1) p = 2 while p * p <= 9999: if prime[p]: i = p * p while i <= 9999: prime[i] = False i = i + p p = p + 1 # v = [] for i in range(1000, n + 1): if prime[i]: v.append(i) return v def compare(a, b): diff = 0 while a: if a % 10 != b % 10: diff += 1 a //= 10 b //= 10 # If the numbers differ only by a single # digit return true else false if diff > 1: return False return True def shortestPath(num1, num2): # Generate all 4 digit pset = [] SieveOfEratosthenes(pset) # Create a graph where node numbers # are indexes in pset[] and there is # an edge between two nodes only if # they differ by single digit. g = Graph(len(pset)) for i in range(len(pset)): for j in range(i + 1, len(pset)): if compare(pset[i], pset[j]): g.addedge(i, j) # Since graph nodes represent indexes # of numbers in pset[], we find indexes of num1 and num2. in1, in2 = None, None for j in range(len(pset)): if pset[j] == num1: in1 = j for j in range(len(pset)): if pset[j] == num2: in2 = j return g.bfs(in1, in2) # Driver code if __name__ == '__main__': num1 = 1033 num2 = 8179 print(shortestPath(num1, num2))
Generate 10-digit number using a phone keypad
Given a phone keypad as shown below: 1 2 3 4 5 6 7 8 9 0 How many different 10-digit numbers can be formed starting from 1? The constraint is that the movement from 1 digit to the next is similar to the movement of the Knight in a chess game. For eg. if we are at 1 then the next digit can be either 6 or 8 if we are at 6 then the next digit can be 1, 7 or 0. Repetition of digits are allowed - 1616161616 is a valid number. Is there a polynomial time algorithm which solves this problem? The problem requires us to just give the count of 10-digit numbers and not necessarily list the numbers. EDIT: I tried modeling this as a graph with each digit having 2 or 3 digits as its neighbors. Then I used DFS to navigate upto the depth of 10 nodes and then increment the count of numbers each time I reached the depth of 10. This obviously is not polynomial time. Assuming each digit had just 2 neighbors, this would have required at least 2^10 iterations. The variable here is the number of digits. I have taken the eg. of 10 digit numbers. It could as well be n-digits.
Sure it can be done in polynomial time. It's an excellent exercise in dynamic programming or memoization. Lets assume N (the number of digits) equals 10 for the example. Think of it recursively like this: How many numbers can I construct using 10 digits starting from 1? Answer is [number of 9-digit numbers starting from 8] + [number of 9-digit numbers starting from 6]. So how many "9-digit numbers starting from 8" are there? Well, [number of 8-digit numbers starting from 1] + [number of 8-digit numbers starting from 3] and so on. Base case is reached when you get the question "How many 1-digit numbers are there starting from X" (and the answer is obviously 1). When it comes to complexity, the key observation is that you reuse previously computed solutions. That is for instance, the answer to "how many 5-digit numbers starting from 3" there are, can be used both when answering "how many 6-digit numbers are there starting from 8" AND "how many 6-digit numbers are there starting from 4". This reuse make the complexity collapse from exponential to polynomial. Let's take a closer look at the complexity of a dynamic programming solution: Such implementation would fill in a matrix in the following way: num[1][i] = 1, for all 0<=i<=9 -- there are one 1-digit number starting from X. for digits = 2...N for from = 0...9 num[digits][from] = num[digits-1][successor 1 of from] + num[digits-1][successor 2 of from] + ... num[digits-1][successor K of from] return num[N][1] -- number of N-digit numbers starting from 1. The algorithm simply fills the matrix one cell at a time, and the matrix is of dimension 10*N, and thus runs in linear time. Wrote it down from the top of my head, please correct me if there are any typos.
I decided to tackle this problem and make it as extensible as I can. This solution allows you to: Define your own board (phone pad, chess board, etc.) Define your own chess piece (Knight, Rook, Bishop, etc.); you will have to write the concrete class and generate it from the factory. Retrieve several pieces of information through some useful utility methods. The classes are as follows: PadNumber: Class defining a button on the phone pad. Could be renamed to 'Square' to represent a board square. ChessPiece: Abstract class that defines fields for all chess pieces. Movement: Interface that defines movement methods and allows for factory generation of pieces. PieceFactory: Factory class to generate Chess pieces. Knight: Concrete class that inherits from ChessPiece and implements Movement PhoneChess: Entrance class. Driver: Driver code. OK, here's the code :) package PhoneChess; import java.awt.Point; public class PadNumber { private String number = ""; private Point coordinates = null; public PadNumber(String number, Point coordinates) { if(number != null && number.isEmpty()==false) this.number = number; else throw new IllegalArgumentException("Input cannot be null or empty."); if(coordinates == null || coordinates.x < 0 || coordinates.y < 0) throw new IllegalArgumentException(); else this.coordinates = coordinates; } public String getNumber() { return this.number; } public Integer getNumberAsNumber() { return Integer.parseInt(this.number); } public Point getCoordinates() { return this.coordinates; } public int getX() { return this.coordinates.x; } public int getY() { return this.coordinates.y; } } ChessPiece package PhoneChess; import java.util.HashMap; import java.util.List; public abstract class ChessPiece implements Movement { protected String name = ""; protected HashMap<PadNumber, List<PadNumber>> moves = null; protected Integer fullNumbers = 0; protected int[] movesFrom = null; protected PadNumber[][] thePad = null; } Movement Interface: package PhoneChess; import java.util.List; public interface Movement { public Integer findNumbers(PadNumber start, Integer digits); public abstract boolean canMove(PadNumber from, PadNumber to); public List<PadNumber> allowedMoves(PadNumber from); public Integer countAllowedMoves(PadNumber from); } PieceFactory package PhoneChess; public class PieceFactory { public ChessPiece getPiece(String piece, PadNumber[][] thePad) { if(thePad == null || thePad.length == 0 || thePad[0].length == 0) throw new IllegalArgumentException("Invalid pad"); if(piece == null) throw new IllegalArgumentException("Invalid chess piece"); if(piece.equalsIgnoreCase("Knight")) return new Knight("Knight", thePad); else return null; } } Knight class package PhoneChess; import java.util.ArrayList; import java.util.HashMap; import java.util.List; public final class Knight extends ChessPiece implements Movement { /**Knight movements * One horizontal, followed by two vertical * Or * One vertical, followed by two horizontal * #param name */ public Knight(String name, PadNumber[][] thePad) { if(name == null || name.isEmpty() == true) throw new IllegalArgumentException("Name cannot be null or empty"); this.name = name; this.thePad = thePad; this.moves = new HashMap<>(); } private Integer fullNumbers = null; #Override public Integer findNumbers(PadNumber start, Integer digits) { if(start == null || "*".equals(start.getNumber()) || "#".equals(start.getNumber()) ) { throw new IllegalArgumentException("Invalid start point"); } if(start.getNumberAsNumber() == 5) { return 0; } //Consider adding an 'allowSpecialChars' condition if(digits == 1) { return 1; }; //Init this.movesFrom = new int[thePad.length * thePad[0].length]; for(int i = 0; i < this.movesFrom.length; i++) this.movesFrom[i] = -1; fullNumbers = 0; findNumbers(start, digits, 1); return fullNumbers; } private void findNumbers(PadNumber start, Integer digits, Integer currentDigits) { //Base condition if(currentDigits == digits) { //Reset currentDigits = 1; fullNumbers++; return; } if(!this.moves.containsKey(start)) allowedMoves(start); List<PadNumber> options = this.moves.get(start); if(options != null) { currentDigits++; //More digits to be got for(PadNumber option : options) findNumbers(option, digits, currentDigits); } } #Override public boolean canMove(PadNumber from, PadNumber to) { //Is the moves list available? if(!this.moves.containsKey(from.getNumber())) { //No? Process. allowedMoves(from); } if(this.moves.get(from) != null) { for(PadNumber option : this.moves.get(from)) { if(option.getNumber().equals(to.getNumber())) return true; } } return false; } /*** * Overriden method that defines each Piece's movement restrictions. */ #Override public List<PadNumber> allowedMoves(PadNumber from) { //First encounter if(this.moves == null) this.moves = new HashMap<>(); if(this.moves.containsKey(from)) return this.moves.get(from); else { List<PadNumber> found = new ArrayList<>(); int row = from.getY();//rows int col = from.getX();//columns //Cases: //1. One horizontal move each way followed by two vertical moves each way if(col-1 >= 0 && row-2 >= 0)//valid { if(thePad[row-2][col-1].getNumber().equals("*") == false && thePad[row-2][col-1].getNumber().equals("#") == false) { found.add(thePad[row-2][col-1]); this.movesFrom[from.getNumberAsNumber()] = this.movesFrom[from.getNumberAsNumber()] + 1; } } if(col-1 >= 0 && row+2 < thePad.length)//valid { if(thePad[row+2][col-1].getNumber().equals("*") == false && thePad[row+2][col-1].getNumber().equals("#") == false) { found.add(thePad[row+2][col-1]); this.movesFrom[from.getNumberAsNumber()] = this.movesFrom[from.getNumberAsNumber()] + 1; } } if(col+1 < thePad[0].length && row+2 < thePad.length)//valid { if(thePad[row+2][col+1].getNumber().equals("*") == false && thePad[row+2][col+1].getNumber().equals("#") == false) { found.add(thePad[row+2][col+1]); this.movesFrom[from.getNumberAsNumber()] = this.movesFrom[from.getNumberAsNumber()] + 1; } } if(col+1 < thePad[0].length && row-2 >= 0)//valid { if(thePad[row-2][col+1].getNumber().equals("*") == false && thePad[row-2][col+1].getNumber().equals("#") == false) found.add(thePad[row-2][col+1]); } //Case 2. One vertical move each way follow by two horizontal moves each way if(col-2 >= 0 && row-1 >= 0) { if(thePad[row-1][col-2].getNumber().equals("*") == false && thePad[row-1][col-2].getNumber().equals("#") == false) found.add(thePad[row-1][col-2]); } if(col-2 >= 0 && row+1 < thePad.length) { if(thePad[row+1][col-2].getNumber().equals("*") == false && thePad[row+1][col-2].getNumber().equals("#") == false) found.add(thePad[row+1][col-2]); } if(col+2 < thePad[0].length && row-1 >= 0) { if(thePad[row-1][col+2].getNumber().equals("*") == false && thePad[row-1][col+2].getNumber().equals("#") == false) found.add(thePad[row-1][col+2]); } if(col+2 < thePad[0].length && row+1 < thePad.length) { if(thePad[row+1][col+2].getNumber().equals("*") == false && thePad[row+1][col+2].getNumber().equals("#") == false) found.add(thePad[row+1][col+2]); } if(found.size() > 0) { this.moves.put(from, found); this.movesFrom[from.getNumberAsNumber()] = found.size(); } else { this.moves.put(from, null); //for example the Knight cannot move from 5 to anywhere this.movesFrom[from.getNumberAsNumber()] = 0; } } return this.moves.get(from); } #Override public Integer countAllowedMoves(PadNumber from) { int start = from.getNumberAsNumber(); if(movesFrom[start] != -1) return movesFrom[start]; else { movesFrom[start] = allowedMoves(from).size(); } return movesFrom[start]; } #Override public String toString() { return this.name; } } PhoneChess entrant class package PhoneChess; public final class PhoneChess { private ChessPiece thePiece = null; private PieceFactory factory = null; public ChessPiece ThePiece() { return this.thePiece; } public PhoneChess(PadNumber[][] thePad, String piece) { if(thePad == null || thePad.length == 0 || thePad[0].length == 0) throw new IllegalArgumentException("Invalid pad"); if(piece == null) throw new IllegalArgumentException("Invalid chess piece"); this.factory = new PieceFactory(); this.thePiece = this.factory.getPiece(piece, thePad); } public Integer findPossibleDigits(PadNumber start, Integer digits) { if(digits <= 0) throw new IllegalArgumentException("Digits cannot be less than or equal to zero"); return thePiece.findNumbers(start, digits); } public boolean isValidMove(PadNumber from, PadNumber to) { return this.thePiece.canMove(from, to); } } Driver Code: public static void main(String[] args) { PadNumber[][] thePad = new PadNumber[4][3]; thePad[0][0] = new PadNumber("1", new Point(0,0)); thePad[0][1] = new PadNumber("2", new Point(1,0)); thePad[0][2] = new PadNumber("3",new Point(2,0)); thePad[1][0] = new PadNumber("4",new Point(0,1)); thePad[1][1] = new PadNumber("5",new Point(1,1)); thePad[1][2] = new PadNumber("6", new Point(2,1)); thePad[2][0] = new PadNumber("7", new Point(0,2)); thePad[2][1] = new PadNumber("8", new Point(1,2)); thePad[2][2] = new PadNumber("9", new Point(2,2)); thePad[3][0] = new PadNumber("*", new Point(0,3)); thePad[3][1] = new PadNumber("0", new Point(1,3)); thePad[3][2] = new PadNumber("#", new Point(2,3)); PhoneChess phoneChess = new PhoneChess(thePad, "Knight"); System.out.println(phoneChess.findPossibleDigits(thePad[0][1],4)); } }
This can be done in O(log N). Consider the keypad and the possible moves on it as a graph G(V, E) where vertices are the available digits and edges say which digits can follow which. Now for each output position i we can form a vector Paths(i) containing the number of different paths each vertex can be reached in. Now it's pretty easy to see that for a given position i and digit v, the possible paths that it can be reached through is the sum of the different paths that possible preceding digits could be reached through, or Paths(i)[v] = sum(Paths(i-1)[v2] * (1 if (v,v2) in E else 0) for v2 in V ). Now, this is taking the sum of each position the preceding vector times a corresponding position in a column of the adjacency matrix. So we can simplify this as Paths(i) = Paths(i-1) · A, where A is the adjacency matrix of the graph. Getting rid of the recursion and taking advantage of associativity of matrix multiplication, this becomes Paths(i) = Paths(1) · A^(i-1). We know Paths(1): we have only one path, to the digit 1. The total number of paths for an n digit number is the sum of the paths for each digit, so the final algorithm becomes: TotalPaths(n) = sum( [1,0,0,0,0,0,0,0,0,0] · A^(n-1) ) The exponentiation can be calculated via squaring in O(log(n)) time, given constant time multiplies, otherwise O(M(n) * log(n)) where M(n) is the complexity of your favorite arbitrary precision multiplication algorithm for n digit numbers.
A simpler answer. #include<stdio.h> int a[10] = {2,2,2,2,3,0,3,2,2,2}; int b[10][3] = {{4,6},{6,8},{7,9},{4,8},{0,3,9},{},{1,7,0},{2,6},{1,3},{2,4}}; int count(int curr,int n) { int sum = 0; if(n==10) return 1; else { int i = 0; int val = 0; for(i = 0; i < a[curr]; i++) { val = count(b[curr][i],n+1); sum += val; } return sum; } } int main() { int n = 1; int val = count(1,0); printf("%d\n",val); } celebrate!!
Run time constant time solution: #include <iostream> constexpr int notValid(int x, int y) { return !(( 1 == x && 3 == y ) || //zero on bottom. ( 0 <= x && 3 > x && //1-9 0 <= y && 3 > y )); } class Knight { template<unsigned N > constexpr int move(int x, int y) { return notValid(x,y)? 0 : jump<N-1>(x,y); } template<unsigned N> constexpr int jump( int x, int y ) { return move<N>(x+1, y-2) + move<N>(x-1, y-2) + move<N>(x+1, y+2) + move<N>(x-1, y+2) + move<N>(x+2, y+1) + move<N>(x-2, y+1) + move<N>(x+2, y-1) + move<N>(x-2, y-1); } public: template<unsigned N> constexpr int count() { return move<N-1>(0,1) + move<N-1>(0,2) + move<N-1>(1,0) + move<N-1>(1,1) + move<N-1>(1,2) + move<N-1>(2,0) + move<N-1>(2,1) + move<N-1>(2,2); } }; template<> constexpr int Knight::move<0>(int x, int y) { return notValid(x,y)? 0 : 1; } template<> constexpr int Knight::count<0>() { return 0; } //terminal cases. template<> constexpr int Knight::count<1>() { return 8; } int main(int argc, char* argv[]) { static_assert( ( 16 == Knight().count<2>() ), "Fail on test with 2 lenght" ); // prof of performance static_assert( ( 35 == Knight().count<3>() ), "Fail on test with 3 lenght" ); std::cout<< "Number of valid Knight phones numbers:" << Knight().count<10>() << std::endl; return 0; }
Method returns list of 10 digit numbers starting with 1. Again the count is 1424. public ArrayList<String> getList(int digit, int length, String base ){ ArrayList<String> list = new ArrayList<String>(); if(length == 1){ list.add(base); return list; } ArrayList<String> temp; for(int i : b[digit]){ String newBase = base +i; list.addAll(getList(i, length -1, newBase )); } return list; }
I'm not sure if I missed something, but reading the description of the problem I came to this solution. It has O(n) time complexity and O(1) space complexity. I figured that number 1 is at a corner, right? In each corner you can either move to one of the sides (4 from 9 and 3, or 6 from 7 an 1) or one of the 'vertical' sides (8 from 3 and 1, or 2 from 9 and 7). So, corners add two moves: a side move and a 'vertical' move. This is true for all four corners (1,3,9,7). From each side, you can either move to two corners (7 and 1 from 6, 9 and 3 from 4) or you can reach the bottom key (0). That's three moves. Two corners and one bottom. On the bottom key (0), you can move to both sides (4 and 6). So, in each step, you check out all possible endings for the path of the previous length (that is, how many ended on a corner, a side, a 'vertical' or the 'bottom' zero key) and then generate new ending counts according to the generation rules stated before. Each corner ending adds a side and a vertical. Each side ending adds 2 corners and a bottom. Each vertical ending adds 2 corners. Each bottom ending adds 2 sides. If you start from the '1' key, you start with one possible corner solution, in each step you count the number of corner, side, vertical and bottom endings of the previous step and then apply the rules to generate the next count. In plain javascript code. function paths(n) { //Index to 0 var corners = 1; var verticals = 0; var bottom = 0; var sides = 0; if (n <= 0) { //No moves possible for paths without length return 0; } for (var i = 1; i < n; i++) { var previousCorners = corners; var previousVerticals = verticals; var previousBottom = bottom; var previousSides = sides; sides = 1 * previousCorners + 2 * previousBottom; verticals = 1 * previousCorners; bottom = 1 * previousSides; corners = 2 * previousSides + 2 * previousVerticals; //console.log("Moves: %d, Length: %d, Sides: %d, Verticals: %d, Bottom: %d, Corners: %d, Total: %d", i, i + 1, sides, verticals, bottom, corners, sides+verticals+bottom+corners); } return sides + verticals + bottom + corners; } for (var i = 0; i <= 10; i++) { console.log(paths(i)); }
This problem may be also modelled as a Constraint satisfaction problem (aka CSP for short). I suggest to use the Minion solver (fast and scalable) that you can find here. Modelling maybe tedious and time consumming (steep learning curve). Instead of using Minion language input, my advice is to formulate the model with solver independent modelling language such as ESSENCE and find a converter accordingly.
//Both the iterative and recursive with memorize shows count as 1424 for 10 digit numbers starting with 1. int[][] b = {{4,6},{6,8},{7,9},{4,8},{0,3,9},{},{1,7,0},{2,6},{1,3},{2,4}}; public int countIterative(int digit, int length) { int[][] matrix = new int[length][10]; for(int dig =0; dig <=9; dig++){ matrix[0][dig] = 1; } for(int len = 1; len < length; len++){ for(int dig =0; dig <=9; dig++){ int sum = 0; for(int i : b[dig]){ sum += matrix[len-1][i]; } matrix[len][dig] = sum; } } return matrix[length-1][digit]; } public int count(int index, int length, int[][] matrix ){ int sum = 0; if(matrix[length-1][index] > 0){ System.out.println("getting value from memoize:"+index + "length:"+ length); return matrix[length-1][index]; } if( length == 1){ return 1; } for(int i: b[index] ) { sum += count(i, length-1,matrix); } matrix[length-1][index] = sum; return sum; }
Recursive memoization approach: vector<vector<int>> lupt = { {4, 6}, {6, 8}, {9, 7}, {4, 8}, {3, 9, 0}, {}, {1,7,0}, {6, 2}, {1, 3}, {2, 4} }; int numPhoneNumbersUtil(int startdigit, int& phonenumberlength, int currCount, map< pair<int,int>,int>& memT) { int noOfCombs = 0; vector<int> enddigits; auto it = memT.find(make_pair(startdigit,currCount)); if(it != memT.end()) { noOfCombs = it->second; return noOfCombs; } if(currCount == phonenumberlength) { return 1; } enddigits = lupt[startdigit]; for(auto it : enddigits) { noOfCombs += numPhoneNumbersUtil(it, phonenumberlength, currCount + 1, memT); } memT.insert(make_pair(make_pair(startdigit,currCount), noOfCombs)); return memT[make_pair(startdigit,currCount)]; } int numPhoneNumbers(int startdigit, int phonenumberlength) { map<pair<int,int>,int> memT; int currentCount = 1; //the first digit has already been added return numPhoneNumbersUtil(startdigit, phonenumberlength, currentCount, memT); }
I implemented both brute force and dynamic programming models import queue def chess_numbers_bf(start, length): if length <= 0: return 0 phone = [[7, 5], [6, 8], [3, 7], [9, 2, 8], [], [6, 9, 0], [1, 5], [0, 2], [3, 1], [5, 3]] total = 0 q = queue.Queue() q.put((start, 1)) while not q.empty(): front = q.get() val = front[0] len_ = front[1] if len_ < length: for elm in phone[val]: q.put((elm, len_ + 1)) else: total += 1 return total def chess_numbers_dp(start, length): if length <= 0: return 0 phone = [[7, 5], [6, 8], [3, 7], [9, 2, 8], [], [6, 9, 0], [1, 5], [0, 2], [3, 1], [5, 3]] memory = {} def __chess_numbers_dp(s, l): if (s, l) in memory: return memory[(s, l)] elif l == length - 1: memory[(s, l)] = 1 return 1 else: total_n_ways = 0 for number in phone[s]: total_n_ways += __chess_numbers_dp(number, l+1) memory[(s, l)] = total_n_ways return total_n_ways return __chess_numbers_dp(start, 0) # bf for i in range(0, 10): print(i, chess_numbers_bf(3, i)) print('\n') for i in range(0, 10): print(i, chess_numbers_bf(9, i)) print('\n') # dp for i in range(0, 10): print(i, chess_numbers_dp(3, i)) print('\n') # dp for i in range(0, 10): print(i, chess_numbers_dp(9, i)) print('\n')
Recursive function in Java: public static int countPhoneNumbers (int n, int r, int c) { if (outOfBounds(r,c)) { return 0; } else { char button = buttons[r][c]; if (button == '.') { // visited return 0; } else { buttons[r][c] = '.'; // record this position so don't revisit. // Count all possible phone numbers with one less digit starting int result=0; result = countPhoneNumbers(n-1,r-2,c-1) + countPhoneNumbers(n-1,r-2,c+1) + countPhoneNumbers(n-1,r+2,c-1) + countPhoneNumbers(n-1,r+2,c+1) + countPhoneNumbers(n-1,r-1,c-2) + countPhoneNumbers(n-1,r-1,c+2) + countPhoneNumbers(n-1,r+1,c-2) + countPhoneNumbers(n-1,r+1,c+2); } buttons[r][c] = button; // Remove record from position. return result; } } }