Minimum number with 0 and 1 divisible by n [duplicate] - algorithm
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.
Related
Numbers ending in 3 have at least one multiple having all ones
Hi Here is a Q that was asked in Adobe Interview. Numbers ending in 3 have at least one multiple having all ones. for eg., 3 and 13 have amultiples like 111 and 111111 respectively. Given such a no. , find the smallest such multiple of that number. The multiple can exceed the range of int, long. You cannot use any complex data structure. Can you provide me with an efficient solution
got the answer now :) int count=1, rem=1; while(rem) { rem= (rem*10+1)%n; count++; } while(count--){ cout<<"1";}
Here is an attempt to do it more efficiently that trying 1, 11, 111, 111.. Could this pay off. Is there a more elegant answer better than trying numbers one at a time? Write the numbers 1, 11, 111, ... as (10^k - 1) / 9, where the division is known to be exact. Given a target number in the form 10x+3 we want to find the smallest k solving (10^k - 1) / 9 = Y(10x + 3) where Y is an integer. Look for small solutions of 10^k = 1 mod 9(10x + 3). This is http://en.wikipedia.org/wiki/Discrete_logarithm except that arithmetic mod 9(10x + 3) does not necessarily form a group - however the http://en.wikipedia.org/wiki/Baby-step_giant-step algorithm should still apply and could be used to search steadily increasing ranges of k, instead of searching possible values of k one at a time.
#include <iostream> using namespace std; int main() { int t; cin>>t; while(t--){ long long n; cin>>n; long long cur = 1; while(cur%n!=0){ cur = cur*10+1; } cout<<cur<<endl; } return 0; }
Solution independent of output size: public String ones(int n) { int i, m = 1; String num="1"; for (i = 1; i <= n; i++) { if (m == 0) return num; /* Solution found */ num=num+"1"; m = (10*m + 1) % n; } return null; /* No solution */ }
If you are looking for a Solution in Java, here it is public static void main(String[] args) { int input = 13; // this can be any number ending with 3 int minAllOnesNum = 1; int nextAllOnesNum= minAllOnesNum; int numberof1s=1; int count = 0; while(true) { count++; if(nextAllOnesNum%input == 0 ) { break; } nextAllOnesNum = nextAllOnesNum*10 + 1; if(nextAllOnesNum>=input) { nextAllOnesNum%=input; } numberof1s++; } System.out.println("Number of iterations : " + count); for(int i=1; i<=numberof1s; i++) { System.out.print("1"); } }
If you are looking for a Solution in Java, here it is public static void main(String[] args) { int input = 55333; int minAllOnesNum = 1; int nextAllOnesNum= minAllOnesNum; int numberof1s=1; int count = 0; while(true) { count++; if(nextAllOnesNum%input == 0 ) { break; } nextAllOnesNum = nextAllOnesNum*10 + 1; if(nextAllOnesNum>=input) { nextAllOnesNum%=input; } numberof1s++; } System.out.println("Number of Iterations: " + count); for(int i=1; i<=numberof1s; i++) { System.out.print("1"); } }
static int findOnes(int num){ int i = 1 ; int power = 0; while (i % num != 0){ i = (i * (10^power)) + 1; } return i; }
Variant of subset sum
I read through all subset sum topics and still have issues with implementing the algorithm for the following problem. Given the array A of N integers (N<=20) where a[i]<=20 values do not have to be unique and an integer K (K<=20). Rules: Array items equal to K are "covered" with K. If sum of two or more array numbers is equal to K, these numbers are also covered. Each number in the array can be covered only once. Example: N=6, integers: 1, 1, 2, 3, 4, 5 K=4 Possible coverages: coverage 4 is covered. 1, 1, 2 are covered as 1+1+2=4. coverage 4 is covered. 1, 3 are covered as 1+3=4. K=5 Possible coverages: coverage 5 is covered. 1,1,3 are covered as 1+1+3=5. coverage 5 is covered. 1,4 are covered as 1+4=5. 2,3 are covered as 2+3=5. Goal: For given array A and integer K, find all possible "coverages". I need all coverages, not only one which covers most of the array items. I have tried with two approaches: Brut force algorithm. Checking all possible subsets of all possible sizes works, but takes too much time even for only 10 numbers. I need it to finish in no more than 500ms. First, I sorted the array in descending order. Then for each possible number of sub-sums I create "slots". I loop through the array and put numbers in the slots following the rules like: Put number in the slot if its sum becomes equal to K. Put number in the slot having the least sum of all slots. Put number in the slot which gives the closet sum to K of all slots. Well, the second approach works and works fast. But I found scenarios where some coverages are not found. I would appreciate if somebody offered idea for solving this problem. I hope I explained the problem well. Thanks.
I don't have ready answer for that, but I recommend to take a look on 'Bin packing problem' it could be usefull here. The main problem is to find all possible sums giving number K. So try this: Collection All_Possible_Sums_GivingK; find_All_Sums_Equal_To_K(Integer K, Array A) { /* this function after finding result add it to global Collection AllPossibleSumsGivingK; */ find_All_Elements_Equal_To_K(Integer K, Array A); Array B = Remove_Elements_Geater_Or_Equal_To_K(Integer K, Array A); for all a in A { find_All_Sums_Equal_To_K(Integer K-a, Array B-a) } }
I modified this from an earlier answer I gave to a different subset sum variant: https://stackoverflow.com/a/10612601/120169 I am running it here on the K=8 case with the above numbers, where we reuse 1 in two different places for one of the two "coverages". Let me know how it works for you. public class TurboAdder2 { // Problem inputs // The unique values private static final int[] data = new int[] { 1, 2, 3, 4, 5 }; // counts[i] = the number of copies of i private static final int[] counts = new int[] { 2, 1, 1, 1, 1 }; // The sum we want to achieve private static int target = 8; private static class Node { public final int index; public final int count; public final Node prevInList; public final int prevSum; public Node(int index, int count, Node prevInList, int prevSum) { this.index = index; this.count = count; this.prevInList = prevInList; this.prevSum = prevSum; } } private static Node sums[] = new Node[target+1]; // Only for use by printString and isSolvable. private static int forbiddenValues[] = new int[data.length]; private static boolean isSolvable(Node n) { if (n == null) { return true; } else { while (n != null) { int idx = n.index; // We prevent recursion on a value already seen. // Don't use any indexes smaller than lastIdx if (forbiddenValues[idx] + n.count <= counts[idx]) { // Verify that none of the bigger indexes are set forbiddenValues[idx] += n.count; boolean ret = isSolvable(sums[n.prevSum]); forbiddenValues[idx] -= n.count; if (ret) { return true; } } n = n.prevInList; } return false; } } public static void printString(String prev, Node n, int firstIdx, int lastIdx) { if (n == null) { printString(prev +" |", sums[target], -1, firstIdx); } else { if (firstIdx == -1 && !isSolvable(sums[target])) { int lidx = prev.lastIndexOf("|"); if (lidx != -1) { System.out.println(prev.substring(0, lidx)); } } else { while (n != null) { int idx = n.index; // We prevent recursion on a value already seen. // Don't use any indexes larger than lastIdx if (forbiddenValues[idx] + n.count <= counts[idx] && (lastIdx < 0 || idx < lastIdx)) { // Verify that none of the bigger indexes are set forbiddenValues[idx] += n.count; printString((prev == null ? "" : (prev + (prev.charAt(prev.length()-1) == '|' ? " " : " + ")))+data[idx]+"*"+n.count, sums[n.prevSum], (firstIdx == -1 ? idx : firstIdx), idx); forbiddenValues[idx] -= n.count; } n = n.prevInList; } } } } public static void main(String[] args) { for (int i = 0; i < data.length; i++) { int value = data[i]; for (int count = 1, sum = value; count <= counts[i] && sum <= target; count++, sum += value) { for (int newsum = sum+1; newsum <= target; newsum++) { if (sums[newsum - sum] != null) { sums[newsum] = new Node(i, count, sums[newsum], newsum - sum); } } } for (int count = 1, sum = value; count <= counts[i] && sum <= target; count++, sum += value) { sums[sum] = new Node(i, count, sums[sum], 0); } } printString(null, sums[target], -1, -1); } }
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; } } }