A* Search Algorithm Not Giving the Optimal Path - algorithm

I am trying to create a MATLAB script for A* Search Algorithm. I created a script. I tried it with a 6-node graph, and computed the correct path. However, this time I tried the script for a different graph (with 12 nodes) and this time I received a wrong answer.
These are the node information nodes.csv file:
Node number, (x, y) coords, heuristic cost
1, -0.5,-0.5, 1.4142
2, -0.09,-0.4, 1.0762
3, -0.285,-0.305, 1.1244
4, 0.0575,-0.225, 0.8494
5, -0.0525,-0.0175, 0.7604
6, -0.37,0.3, 0.8927
7, 0.3525,-0.0525, 0.5719
8, 0.0625,0.255, 0.5014
9, -0.1,0.3725, 0.6134
10, 0.4275,0.195, 0.3135
11, 0.345,0.3525, 0.214
12, 0.5,0.5, 0
These are the edge informations from edges.csv file (edges are undirected):
Node 1, Node 2, Cost
12, 11, 0.214
12, 10, 0.3135
12, 8, 0.5014
11, 10, 0.1778
11, 9, 0.4454
10, 7, 0.2586
9, 8, 0.2005
9, 6, 0.2796
9, 5, 0.5994
8, 4, 0.48
7, 4, 0.3417
5, 2, 0.179
4, 3, 0.3517
4, 2, 0.2289
3, 2, 0.2169
3, 1, 0.2903
2, 1, 0.422
7, 5, 0.4402
5, 4, 0.11
The solution to the graph is: 1 - 3 - 4 - 7 - 10 - 12.
The path my script calculated is: 1 - 3 - 4 - 2 - 5 - 5 - 7 - 10 - 12.
Notice that node 5 is shown twice, which I have no idea about. I tried to debug, but could not find what was the incorrect part.
Here is my code:
clc
clear
%% Constructing the Nodes with their information:
% Assigning the adjacent node information to nodes:
nodes = readmatrix('nodes.csv');
edges = readmatrix('edges.csv');
node(1).successors = [2 3];
node(2).successors = [3 4 5];
node(3).successors = [1 2 4];
node(4).successors = [5 2 3 7 8];
node(5).successors = [4 7 2 9];
node(6).successors = 9;
node(7).successors = [5 4 10];
node(8).successors = [4 9 12];
node(9).successors = [5 6 8 11];
node(10).successors = [7 11 12];
node(11).successors = [9 10 12];
node(12).successors = [8 10 11];
% Assigning heuristic cost values and cost numbers to nodes:
heuristics = nodes(:,4);
for i = 1 : length(nodes)
node(i).heuristic = heuristics(i);
node(i).order = i;
end
% Initializing the pastCost and totalCost of the nodes:
node(1).pastCost = 0;
node(1).totalCost = node(1).pastCost + node(1). heuristic;
for i = 2 : length(nodes)
node(i).pastCost = Inf;
node(i).totalCost = node(i).pastCost + node(i). heuristic;
end
nodeStart = nodes(1, 1);
nodeGoal = nodes(12, 1);
% Node start has no parent node:
node(nodeStart).parent = [];
% Adding the first node to OPEN List
OPEN = {node(1)};
CLOSED = {};
%% Starting the A* Search Algorithm:
% If tthe OPEN list is not empty, iterations are going to start:
while(~isempty(OPEN))
current = OPEN{1};
OPEN(1) = [];
CLOSED{length(CLOSED) + 1} = current;
% If the current node is the goal node, algorithm is finished with
% success, return the path from the CLOSED List:
if (current.order == nodeGoal)
disp('SUCCESS!')
for i = 1 : length(CLOSED)
fprintf(' %d ', CLOSED{i}.order)
end
return
end
% Creating an array which consists of the node numbers of the closed nodes:
for i = 1 : length(CLOSED)
closedNodes(i) = CLOSED{i}.order;
end
% Starting searching through the adjacents/successors of the current node:
for i = 1 : length(current.successors)
% If the current node is not in the CLOSED List / member of the
% closedNodes array, calculations are going to be taking place:
if (~ismember(current.successors(i), closedNodes))
tentativePastCost = current.pastCost + edgeCost(current.order, current.successors(i), edges);
if (tentativePastCost < node(current.successors(i)).pastCost)
node(current.successors(i)).pastCost = tentativePastCost;
node(current.successors(i)).parent = current.order;
node(current.successors(i)).totalCost = node(current.successors(i)).pastCost + node(current.successors(i)).heuristic;
% Adding the current node to the OPEN List and then sorting
% the OPEN List with respect to total cost values:
if(length(OPEN) == 0 || node(current.successors(i)).order ~= OPEN{length(OPEN)}.order)
OPEN{length(OPEN) + 1} = node(current.successors(i));
end
[~,I] = sort(cellfun(#(s) getfield(s,"totalCost"), OPEN));
OPEN = OPEN(I);
end
end
end
end
disp('FAILURE!')
What is the reason my program jumps from node 4 to 2, instead of node 7?

Related

How to draw an n sample from U(a,b) of numbers not close?

I need to draw an n sample from the uniform distribution on the interval [a,b] such that no two numbers are closer than d > 0. I can draw a sample and check this property and then throw it away and try again if not, but if n is large relative to b-a that could take a looong time. Is there a simple and nice algorithm to solve this problem? The numbers got to be uniformly distributed on [a,b], no deterministic setup.
This problem is equivalent to choosing n numbers greater than or equal to d and whose sum is equal to b - a.
There will be some solution provided that n * d <= b - a. We can write a recursive algorithm that looks for one:
b - a - X < (n - 1) * D
X > b - a - (n - 1) * d
FindSpacedSample(n, d, a, b)
1. if n * d > b - a then return "no solution"
2. avail = [d, b - a - (n - 1) * d]
3. guess = random(avail)
4. print(guess)
5. FindSpacedSample(n - 1, d, a + guess, b)
Example: n = 5, a = 0, b = 10, d = 1, assuming real numbers
FindSpacedSample(5, 1, 0, 10)
5 * 1 >? b - a? no
avail = [1, 10 - 0 - 4 * 1] = [1, 6]
guess = random(avail) = 2 (for the sake of argument)
print(2)
FindSpacedSample(4, 1, 2, 10)
4 * 1 >? 10 - 2? no
avail = [1, 10 - 2 - 3 * 1] = [1, 5]
guess = random(avail) = 4 (for the sake of argument)
print(4)
FindSpacedSample(3, 1, 6, 10)
3 * 1 >? 10 - 6? no
avail = [1, 10 - 6 - 2 * 1] = [1, 2]
guess = random(avail) = 1 (for the sake of argument)
print(1)
FindSpacedSample(2, 1, 7, 10)
2 * 1 >? 10 - 7? no
avail = [1, 10 - 7 - 1 * 1] = [1, 2]
guess = random(avail) = 2 (for the sake of argument)
print(2)
FindSpacedSample(1, 1, 9, 10)
1 * 1 >? 10 - 9? no
avail = [1, 10 - 9 - 0 * 1] = [1, 1]
guess = 1
print(1)
We should also have stopping condition n = 0. Then we get the sequence of spaces 2, 4, 1, 2, 1; we see these sum to ten; and we can get the values as follows:
point1 = 2 = 2
point2 = 2 + 4 = 6
point3 = 2 + 4 + 1 = 7
point4 = 2 + 4 + 1 + 2 = 9
point5 = 2 + 4 + 1 + 2 + 1 = 10
Now, there are a couple of ways in which this result is less than totally uniform:
the first number will never be less than d
earlier numbers tend to be spaced further apart
We can fix these by:
shuffling the spacings before converting to points
subtracting from each point some random value from [0, point1 - a].
So, if we shuffled 2, 4, 1, 2, 1 to 4, 1, 1, 2, 2 we'd get points 4, 5, 6, 8, 10; and if we subtracted 3 from each one (taken randomly between 0 and 4) we'd get 1, 2, 3, 5, 7.
Does this give you a uniform distribution over the set of all possible solutions? I'd be surprised if it did, but I'd also be surprised if what this does give you differs from that truly uniform distribution to an appreciable degree.

Find all combinations in a 3x3 matrix following some rules

Given a 3x3 matrix:
|1 2 3|
|4 5 6|
|7 8 9|
I'd like to calculate all the combinations by connecting the numbers in this matrix following these rules:
the combinations width are between 3 and 9
use one number only once
you can only connect adjacent numbers
Some examples: 123, 258, 2589, 123654, etc.
For example 1238 is not a good combination because 3 and 8 are not adjacent. The 123 and the 321 combination is not the same.
I hope my description is clear.
If anyone has any ideas please let me know. Actually I don't know how to start :D. Thanks
This is a search problem. You can just use straightforward depth-first-search with recursive programming to quickly solve the problem. Something like the following:
func search(matrix[N][M], x, y, digitsUsed[10], combination[L]) {
if length(combination) between 3 and 9 {
add this combination into your solution
}
// four adjacent directions to be attempted
dx = {1,0,0,-1}
dy = {0,1,-1,0}
for i = 0; i < 4; i++ {
next_x = x + dx[i]
next_y = y + dy[i]
if in_matrix(next_x, next_y) and not digitsUsed[matrix[next_x][next_y]] {
digitsUsed[matrix[next_x][next_y]] = true
combination += matrix[next_x][next_y]
search(matrix, next_x, next_y, digitsUsed, combination)
// At this time, sub-search starts with (next_x, next_y) has been completed.
digitsUsed[matrix[next_x][next_y]] = false
}
}
}
So you could run search function for every single grid in the matrix, and every combinations in your solution are different from each other because they start from different grids.
In addition, we don't need to record the status which indicates one grid in the matrix has or has not been traversed because every digit can be used only once, so grids which have been traversed will never be traversed again since their digits have been already contained in the combination.
Here is a possible implementation in Python 3 as a a recursive depth-first exploration:
def find_combinations(data, min_length, max_length):
# Matrix of booleans indicating what values have been used
visited = [[False for _ in row] for row in data]
# Current combination
comb = []
# Start recursive algorithm at every possible position
for i in range(len(data)):
for j in range(len(data[i])):
# Add initial combination element and mark as visited
comb.append(data[i][j])
visited[i][j] = True
# Start recursive algorithm
yield from find_combinations_rec(data, min_length, max_length, visited, comb, i, j)
# After all combinations with current element have been produced remove it
visited[i][j] = False
comb.pop()
def find_combinations_rec(data, min_length, max_length, visited, comb, i, j):
# Yield the current combination if it has the right size
if min_length <= len(comb) <= max_length:
yield comb.copy()
# Stop the recursion after reaching maximum length
if len(comb) >= max_length:
return
# For each neighbor of the last added element
for i2, j2 in ((i - 1, j), (i, j - 1), (i, j + 1), (i + 1, j)):
# Check the neighbor is valid and not visited
if i2 < 0 or i2 >= len(data) or j2 < 0 or j2 >= len(data[i2]) or visited[i2][j2]:
continue
# Add neighbor and mark as visited
comb.append(data[i2][j2])
visited[i2][j2] = True
# Produce combinations for current starting sequence
yield from find_combinations_rec(data, min_length, max_length, visited, comb, i2, j2)
# Remove last added combination element
visited[i2][j2] = False
comb.pop()
# Try it
data = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
min_length = 3
max_length = 9
for comb in find_combinations(data, min_length, max_length):
print(c)
Output:
[1, 2, 3]
[1, 2, 3, 6]
[1, 2, 3, 6, 5]
[1, 2, 3, 6, 5, 4]
[1, 2, 3, 6, 5, 4, 7]
[1, 2, 3, 6, 5, 4, 7, 8]
[1, 2, 3, 6, 5, 4, 7, 8, 9]
[1, 2, 3, 6, 5, 8]
[1, 2, 3, 6, 5, 8, 7]
[1, 2, 3, 6, 5, 8, 7, 4]
[1, 2, 3, 6, 5, 8, 9]
[1, 2, 3, 6, 9]
[1, 2, 3, 6, 9, 8]
[1, 2, 3, 6, 9, 8, 5]
[1, 2, 3, 6, 9, 8, 5, 4]
[1, 2, 3, 6, 9, 8, 5, 4, 7]
...
Look at all the combinations and take the connected ones:
import itertools
def coords(n):
"""Coordinates of number n in the matrix."""
return (n - 1) // 3, (n - 1) % 3
def adjacent(a, b):
"""Check if a and b are adjacent in the matrix."""
ai, aj = coords(a)
bi, bj = coords(b)
return abs(ai - bi) + abs(aj - bj) == 1
def connected(comb):
"""Check if combination is connected."""
return all(adjacent(a, b) for a, b in zip(comb, comb[1:]))
for width in range(3, 10):
for comb in itertools.permutations(range(1, 10), width):
if connected(comb):
print(comb)

How do I find the smallest combination of 2 numbers to get closest to another number

I have two numbers: 6 & 10
I want to use a combination of these 2 numbers to get as close as possible to another number.
For example, to get to 9 I need 1 six with 3 remaining.
Other examples:
6: [6]
10: [10]
12: [6, 6]
18: [6, 6, 6]
20: [10, 10]
24: [6, 6, 6, 6]
26: [10, 10, 6]
28: [10, 6, 6, 6]
30: [10, 10, 10]
32: [10, 10, 6, 6]
I need an algorithm that can find the smallest number of combinations for any given number, taking preference for a combination with the smallest remainder. ie
38: [10, 10, 10, 6] - 2 remaining
38: [10, 10, 6, 6, 6] - no remainder, so preferred result
I hope I've explained this clearly, let me know if I need to clarify.
UPDATE:
To clarify, this is a real-world problem dealing with physical goods. The numbers 6 & 10 correspond to package cartons that contain multiples of a product in either 6 or 10 quantities. We accept orders for these products in any amount, and want to calculate the smallest number of cartons that can make up the order, and then add the remainder as individual qtys.
A customer may want to order a qty of 39, so I need to know the smallest number of 6/10 qty cartons to make up the order, with the smallest number of remainders being the priority.
A customer may also order qtys of 1,2,3,4,5,6..... up to a max of about 300.
Considering you want the factorization of n in factors of a and b, then you just need to factorize the two possible ways and check which one gives you the minimal remainder.
So, you can something like this:
def factorize(a, b, n):
return n/a, (n%a)/b, (n%a)%b
def factorize_min(a, b, n):
na1, nb1, r1 = factorize(a, b, n)
nb2, na2, r2 = factorize(b, a, n)
return (na1, nb1) if r1 < r2 else (na2, nb2)
def factorize_min_list(a, b, n):
na, nb = factorize_min(a, b, n)
return [a]*na + [b]*nb
And use it like this:
for n in (6,10,12,18,20,24,26,28,30,32):
print factorize_min_list(6, 10, n)
This would give you:
[6]
[10]
[6, 6]
[6, 6, 6]
[10, 10]
[6, 6, 6, 6]
[6, 10, 10]
[6, 10, 10]
[10, 10, 10]
[10, 10, 10]
This is kind of change-making problem that might be effectively solved using dynamic programming. Note that if needed sum cannot be produced exactly (like 9 in your example) - check lower neighbor cells of the DP table.
This is more or less the coin problem. Above the Frobenius number all values can be built. Here we have 6 and 10 which aren't coprime. So we can divide by the greatest common divisor (2) to get 3 and 5 which are coprime. Then we get the Frobenius number 3*5 - 5 - 3 = 7. This means all even values > 14 can be built using 6 and 10 coins. The values are so few, that you could just make a list:
3 (% 3 = 0), coins (1, 0)
5 (% 3 = 2), coins (0, 1)
6 (% 3 = 0), coins (2, 0)
8 (% 3 = 2), coins (1, 1)
9 (% 3 = 0), coins (3, 0)
10 (% 3 = 1), coins (0, 2)
So the algorithm would be as follows:
divide input by 2
if it is smaller than 11 return the closest of the 6 values in the list
otherwise do input % 3, take corresponding configuration (8, 9 or 10), subtract it from input, divide by 3 and add the result to the 3 (i.e. 6) coins
Example for 32 (or 33):
32 / 2 = 16
16 >= 11
16 % 3 = 1, we take 10 (0, 2), (16 - 10) / 3 = 2, add it to 3 coins => (2, 2)
check: 2 * 6 + 2 * 10 = 32
The following is a C version of solving your problem with dynamic programming.
After you compile it you can run it with the total number of items as parameter
It will output the package sizes 10 and 6 separated by tabs
followed by their sum.
I took the algorithm from the german wikipedia page on the knapsack problem
https://de.m.wikipedia.org/wiki/Rucksackproblem
It is quoted in the comment at the beginning:
/*
U = { 10, 6 } n = 2
w = { 10, 6 }
v = { 2, 1 }
Eingabe: U, B, w, v wie oben beschrieben
R := [1…(n+1), 0…B]-Matrix, mit Einträgen 0
FOR i = n … 1
FOR j = 1 … B
IF w(i) <= j
R[i,j] := max( v(i) + R[i+1, j-w(i)], R[i+1,j]\
)
ELSE
R[i,j] := R[i+1,j]
Ausgabe: R[1,B]
*/
#include <stdlib.h>
#include <stdio.h>
int n = 2;
int main(int argc, char** argv) {
int w[3] = { -1, 10, 6 };
int v[3] = { -1, 10, 6 };
int B = atoi(argv[1]);
size_t sz = ((B+1)*3*sizeof(int));
int* R = malloc(sz);
memset(R, 0, sz);
for(int i = n; i > 0; i--) {
for(int j = 1; j <= B; j++) {
int b = R[i+1,j];
if(w[i] <= j) {
// max( v(i) + R[i+1, j-w(i)], R[i+1,j] )
int a = v[i] + R[i+1, j-w[i]];
R[i,j] = a>b?a:b;
} else {
R[i,j] = b;
}
}
}
int k = R[1,B];
while(R[1,k]>0){
int j = R[1,k];;
for(int i = n; i > 0; i--) {
int t = R[1,k-w[i]];
if(t == k - w[i]) {
j = w[i];
}
}
printf("%i\t",j);
k = k-j;
}
printf("\n%i\n", R[1,B]);
return 0;
}

Sorting permutation efficiently

Given an unsorted permutation of [n], I want to collect the numbers by iterating from left to right in order to sort the premutation (1...n).
What is the number of iteration I have to do in order to acheieve this goal?
For example:
Given '3, 7, 4, 2, 10, 8, 9, 1, 6, 5'- the number of iterations is 6.
In the first iteration I will collect the number 1
In the second iteration I will collect the number 2
In the third iteration I will collect the numbers 3,4,5
In the forth iteration I will collect the number 6
In the fifth iteration I will collect the numbers 7,8,9
In the sixth iteration I will collect the number 10
I build a naive code, doing the task with O(n^2), but I need it to be more efficient, so I think there's a trick I'm missing here.
Any suggestions?
Invert the permutation, then count how many times two consecutive numbers are decreasing, plus one.
def iterations(perm):
invperm = [None] * len(perm)
for i in range(len(perm)): # yes, we could use enumerate
invperm[perm[i] - 1] = i
count = 1
for i in range(1, len(perm)):
count += invperm[i - 1] > invperm[i]
return count
Explaination:
Given : 3, 7, 4, 2, 10, 8, 9, 1, 6, 5
x : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
Index of x in the given array : |8, |4, |1, 3, 10, |9, |2, 6, 7, |5
If indexes are out of order then you have to start again. So if you count |s then you know number of iterations you need.
Since you already know the result, it's unclear to me in what sense you're "sorting" anything. What result are you looking for -- the information about what numbers are "collected" at each iteration, as you show in your Q? In this case here's a simple Python 2 implementation example:
target = 3, 7, 4, 2, 10, 8, 9, 1, 6, 5
def do_permut(targ):
look_for = 1
iter_num = 1
while look_for != len(targ) + 1:
print 'Iteration', iter_num, ':',
for item in targ:
if item == look_for:
print item,
look_for += 1
print
iter_num += 1
do_permut(target)
However the task is inevitably O(N squared) -- remember big-O stands for worst case! You'll have up to N iterations (worst case realized when targ is reverse sorted to start with) each over N numbers -- thus, N squared. You could slightly optimize each iteration by collecting a set of numbers previously seen during it and breaking when look_for is in that set, but that only (roughly) halves each iteration's work, so it's still O(N squared).
If you can explain better what results and outputs you expect from your work we may be able to help more!
Just for curiosity here's a version with the above "improvement" and also a sanity check to ensure it raises an exception, rather than looping forever, if passed a sequence that's NOT a permutation of [1:n)...:
target = 3, 7, 4, 2, 10, 8, 9, 1, 6, 5
def do_permut(targ):
look_for = 1
iter_num = 1
while look_for != len(targ) + 1:
print 'iteration', iter_num, ':',
seen = set()
found_in_iter = 0
for item in targ:
seen.add(item)
if item == look_for:
print item,
found_in_iter += 1
look_for += 1
if look_for in seen:
break
print
if not found_in_iter:
raise ValueError('missing: %s' % look_for)
iter_num += 1
do_permut(target)
If you know that in assumption is given an array where for sure are present all elements of the permutation of [n] then I think:
Allocate an array y[1..n]
In one loop from 1 to n search initial array x of unsorted elements colecting items in each iteration the following way: y[x[i]] := x[i]
After the loop all in y is a sorted permutation with O (n)
-- edited 20-12-2014 22:54 CET:
The solution above works only for situation, where there is n-elementh table of integers from 1 to n unordered in any given way.
I'd like to explain in details how you can achieve the goal with only one iteration through the inpput array basing on your example.
Let's take the initial array:
x[] = { 3, 7, 4, 2, 10, 8, 9, 1, 6, 5 }
As a result let's take the following array filled at start with zero's:
y[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
Now let each item of the following ordered list be an iteration of the sorting algorithm:
We take x[1] which equals 3 - let's write it under 3rd position in result table y:
y[3] := 3 (which in fact is: y[x[1]] := x[1])
the result table now looks like following
y[] = { 0, 0, 3, 0, 0, 0, 0, 0, 0, 0 }
In second step we take x[2] which equals 7 and we repeat the steps:
y[7] := 7 (which in fact is: y[x[2]] := x[2])
the result table now looks like following
y[] = { 0, 0, 3, 0, 0, 0, 7, 0, 0, 0 }
Third step: x[3] which equals 4:
y[4] := 4 (which in fact is: y[x[3]] := x[3])
result table:
y[] = { 0, 0, 3, 4, 0, 0, 7, 0, 0, 0 }
x[4] which equals 2:
y[2] := 2 (which in fact is: y[x[4]] := x[4])
result table:
y[] = { 0, 2, 3, 4, 0, 0, 7, 0, 0, 0 }
x[5] which equals 10:
y[10] := 10 (which in fact is: y[x[5]] := x[5])
result table:
y[] = { 0, 2, 3, 4, 0, 0, 7, 0, 0, 10 }
x[6] which equals 8:
y[8] := 8 (which in fact is: y[x[6]] := x[6])
result table:
y[] = { 0, 2, 3, 4, 0, 0, 7, 8, 0, 10 }
x[7] which equals 9:
y[9] := 9 (which in fact is: y[x[7]] := x[7])
result table:
y[] = { 0, 2, 3, 4, 0, 0, 7, 8, 9, 10 }
x[8] which equals 1:
y[1] := 1 (which in fact is: y[x[8]] := x[8])
result table:
y[] = { 1, 2, 3, 4, 0, 0, 7, 8, 9, 10 }
x[9] which equals 6:
y[6] := 6 (which in fact is: y[x[9]] := x[9])
result table:
y[] = { 1, 2, 3, 4, 0, 6, 7, 8, 9, 10 }
The last iteration:
x[10] which equals 5:
y[5] := 5 (which in fact is: y[x[10]] := x[10])
result table:
y[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
As we can see table y is a fully sorted version of input table x that was generated with 10 iterations (so O(n) cost level).
No matter how big is n and how much unordered is the given input table, with those particular assumptions taken, the cost is constant and equals n;
I hope I didn't misunderstood your question.
I tried to implement your sample in PERL.
#!/usr/bin/perl
if ($#ARGV < 0) { # with no arguments
#data = (3, 7, 4, 2, 10, 8, 9, 1, 6, 5);
}
else {
#tmp = (1..$ARGV[0]);
while(#tmp) {
push(#data, splice(#tmp, rand($#tmp), 1));
}
}
$key = 1;
while (#data) {
#remove = (); #remain = ();
printf "key = $key\t(#data) --> ";
foreach $i (#data) {
if ($i == $key) { # found
push(#remove, $i);
$key++;
}
else {
push(#remain, $i);
}
}
#data = #remain;
print "(#remove) & (#data)\n";
$count++;
}
print "Iteration = $count\n";
As a result.
$ ./a.pl
key = 1 (3 7 4 2 10 8 9 1 6 5) --> (1) & (3 7 4 2 10 8 9 6 5)
key = 2 (3 7 4 2 10 8 9 6 5) --> (2) & (3 7 4 10 8 9 6 5)
key = 3 (3 7 4 10 8 9 6 5) --> (3 4 5) & (7 10 8 9 6)
key = 6 (7 10 8 9 6) --> (6) & (7 10 8 9)
key = 7 (7 10 8 9) --> (7 8 9) & (10)
key = 10 (10) --> (10) & ()
Iteration = 6
$ ./a.pl 10
key = 1 (2 1 4 8 5 9 3 6 7 10) --> (1) & (2 4 8 5 9 3 6 7 10)
key = 2 (2 4 8 5 9 3 6 7 10) --> (2 3) & (4 8 5 9 6 7 10)
key = 4 (4 8 5 9 6 7 10) --> (4 5 6 7) & (8 9 10)
key = 8 (8 9 10) --> (8 9 10) & ()
Iteration = 4
$ ./a.pl 10
key = 1 (3 1 7 8 6 2 9 5 4 10) --> (1 2) & (3 7 8 6 9 5 4 10)
key = 3 (3 7 8 6 9 5 4 10) --> (3 4) & (7 8 6 9 5 10)
key = 5 (7 8 6 9 5 10) --> (5) & (7 8 6 9 10)
key = 6 (7 8 6 9 10) --> (6) & (7 8 9 10)
key = 7 (7 8 9 10) --> (7 8 9 10) & ()
Iteration = 5

Write an algorithm to return an array such that every number k from 1..n is occurring exactly twice and is k distance apart from its replica

This question was asked in an interview.
For a given integer n >= 3 return an array of size 2n such that every number k from 1 to n is occurring exactly twice and every number and its repetition is separated by a distance equal to the number.
Function signature:
int* buildArray(int n)
For example, for n = 3:
3, 1, 2, 1, 3, 2
Number 2: 1st position 3 and 2nd position 6, so distance 6 - 3 - 1 = 2.
Number 3: First 3 at position 1 and 2nd 3 at position 5, so distance 5 - 1 - 1 = 3.
For n = 4:
4, 1, 3, 1, 2, 4, 3, 2
This is an exact cover problem, which you can solve with Algorithm X. (And it's a nicer, simpler example than Sudoku.) You have the following constraints:
each number must be used exaclty twice and
each slot in the array can only be occupied by one number
For your problem with n = 3, you get the following matrix:
[0] [1] [2] [3] [4] [5] 1 2 3
--- --- --- --- --- --- --- --- ---
#0 X X X
#1 X X X
#2 X X X
#3 X X X
#4 X X X
#5 X X X
#6 X X X
#7 X X X
#8 X X X
The columns [x] mean that slot x is used; plain x means that the digit x has been placed. The rows #0 to #3 describe the possible placements of ones, #4 to #6 the placements of twos and #7 and #8 the twi possibilities to place the threes. This will yield the two (mirrored) solutions:
2 3 1 2 1 3 (#2 + #4 + #8)
3 1 2 1 3 2 (#1 + #6 + #7)
Not all n yield solutions, there are no solutions for 5 and 6, for example.
It's a Langford's problem/sequence.
There is a topic about the same problem on SO with implementation already.
Langford sequence implementation Haskell or C
It's NP-complete problem.
However, it can be fairly easily coded-up using recursion and backtracking, making it suitable solution for an interview. It's similar to, for example, N queens puzzle backtracking solution (which was my inspiration).
Ready-to-run code in Java:
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
for (int i = 3; i < 13; i++) {
int[] answer = buildArray(i);
if (answer[0] != 0) {
System.out.println(i + " " + Arrays.toString(answer));
}
}
}
public static int[] buildArray(int n) {
int[] answer = new int[2 * n];
put(answer, n); // start with placing n, later (n - 1), (n - 2), ..., 1
return answer;
}
private static boolean put(int[] answer, int k) {
for (int i = 0; i + k + 1 < answer.length; i++) { // try every posiiton
if (answer[i] == 0 && answer[i + k + 1] == 0) {
answer[i] = k;
answer[i + k + 1] = k;
if (k == 1) {
return true; // we found a solution, escape!
}
if (put(answer, k - 1)) {
return true; // we found a solution, escape!
}
answer[i] = 0; // step back and erase this placement
answer[i + k + 1] = 0;
}
}
return false; // still not full solution, continue
}
}
Output:
3 [3, 1, 2, 1, 3, 2]
4 [4, 1, 3, 1, 2, 4, 3, 2]
7 [7, 3, 6, 2, 5, 3, 2, 4, 7, 6, 5, 1, 4, 1]
8 [8, 3, 7, 2, 6, 3, 2, 4, 5, 8, 7, 6, 4, 1, 5, 1]
11 [11, 6, 10, 2, 9, 3, 2, 8, 6, 3, 7, 5, 11, 10, 9, 4, 8, 5, 7, 1, 4, 1]
12 [12, 10, 11, 6, 4, 5, 9, 7, 8, 4, 6, 5, 10, 12, 11, 7, 9, 8, 3, 1, 2, 1, 3, 2]

Resources