Finding Clusters of Contours based on criteria - visual-studio

I have detected the contours in an image of a barcode, and fount the minrect for each bar. There are other objects in the image, so I'd like to isolate the barcode by finding clusters of similarly angled rectangles.
I am new to C++ opencv, so I'm not really sure what approach I should use. Any suggestions?

vector<vector<int>> RAPC(vector<RotatedRect> minRect, float radius) {
vector<vector<int>> clusters; // vector that will contain identify who belongs to which cluster
vector<bool> touched(minRect.size(), false); // initializing vector that will identify whether or not a rectangle has been assigned to a cluster
// for every rect
for (int i = 0; i < minRect.size()-1; i++)
{
// compare to every other rect
for (int n = (i + 1); n < minRect.size(); n++)
{
// distance from rect i to rect n
float distance = sqrt(pow((minRect[i].center.x - minRect[n].center.x), 2)
+ pow((minRect[i].center.y - minRect[n].center.y), 2));
//criteria to determine whether the two rectangles belong in the same cluster
if ( distance < radius)
{
// if neither rectangle has been assigned to a cluster yet
if (touched[i] == false && touched[n] == false) {
// create new cluster in clusters with i and n as members
clusters.emplace_back(initializer_list<int>{i, n});
touched[i] = true; // make note of i being placed
touched[n] = true; // make note of n being placed
}
// if i has already been assigned to a cluster
else if (touched[i] == true && touched[n] == false) {
int loc = findLoc(i, clusters); // find i in clusters
clusters[loc].emplace_back(n); // place n in that cluster
touched[n] = true; // make note of n being placed
}
// if n has already been assigned to a cluster
else if (touched[n] == true && touched[i] == false) {
int loc = findLoc(n, clusters); // find n in clusters
clusters[loc].emplace_back(i); // place n in that cluster
touched[i] = true; // make note of i being placed
}
// if both rectangles have already been assigned
else (touched[i] == true && touched[n] == true); {
int locI = findLoc(i, clusters); // search for location of i
int locN = findLoc(n, clusters); // search for location of n
// if both rectangles are already part of the same cluster, ignore
if (locI == locN) {
break;
}
// concatenate vector n with vector i
clusters[locI].insert(clusters[locI].end(), clusters[locN].begin(), clusters[locN].end());
// erase original location of vector n
clusters[locN].erase(clusters[locN].begin(), clusters[locN].end());
}
}
}
}
return clusters;
}
// function used by RAPC mainly just to make code more concise
int findLoc(int numSearchedFor, vector<vector<int>> clusters) {
bool searchComplete = false;
int ans; // initializing function output ie the cluster ID where the value is found
for (int i = 0; i < clusters.size(); i++) {
for (int n = 0; n < clusters[i].size(); n++) {
if (clusters[i][n] == numSearchedFor) {
ans = i;
searchComplete = true;
break;
}
}
if (searchComplete == true) {
break;
}
}
return ans;
}

Related

Minimax Algorithm doesn't work as expected

I'm currently working on a checkers game against an AI in c#. I have tried to implement the AI using minimax algorithm. Although my function works the moves it selects are not logical at all. I tested it with many plays and algorithm just select bad moves when there are many better option. I don't think its due to the horizon problem because the move it makes have immediate consequences such as loosing a piece without capturing any of the opponents piece.
Som notes about the code:
My function takes a 8x8 2d array of enum Pieces which represents the checkers board.
BlackPlayer is a bool value within the same class with function.
MyPiece(currentPiece) function checks if the currentPiece is the same color with the AI.
Since capture is mandatory in checkers function first checks if the gameState contains any capture moves. If not checks normal moves.
I used alpha-beta pruning to make it more efficient.
I used CloneGameState(gameState) function to copy the 2d array so that original array that represents the game never changes.
public int Minimax (Pieces[,] gameState, int depth, bool is_maximizing, int alpha, int beta)
{
//Base Case - Return the board value
if (depth == 3)
return HeuristicEvaluation(gameState);
Move[] possibleMoves;
int bestValue;
bool currentSide;
if (is_maximizing)
{
bestValue = int.MinValue;
currentSide = BlackPlayer;
}
else
{
bestValue = int.MaxValue;
currentSide = !BlackPlayer;
}
// check forced moves
int moveCount = rules.GetCaptureMoves(gameState,out possibleMoves, currentSide);
// if no forced moves get normal moves
if (moveCount < 1)
moveCount = rules.GetNormalMoves(gameState,out possibleMoves, currentSide);
// traverse moves
for (int i = 0; i < moveCount; i++)
{
Pieces[,] newGameState = ApplyMove(CloneGameState(gameState), possibleMoves[i]);
int newStateValue = Minimax(newGameState, depth + 1, !is_maximizing,alpha, beta);
if (is_maximizing)
{
if (newStateValue > bestValue)
{
bestValue = newStateValue;
if (depth == 0)
bestMove = possibleMoves[i];
if (newStateValue > alpha)
alpha = newStateValue;
if (alpha >= beta)
return bestValue;
}
}
//Evaluation for min
else
{
if (newStateValue < bestValue)
{
bestValue = newStateValue;
if (newStateValue < beta)
beta = newStateValue;
if (alpha >= beta)
return bestValue;
}
}
}
return bestValue;
}
The heuristics function:
public int HeuristicEvaluation(Pieces[,] gameState)
{
int stateValue = 0;
//use loops to check each piece
for (int j = 0; j < 8; j++)
{
int i = 0;
if (j % 2 == 1)
i++;
for (; i < 8; i += 2)
{
Pieces currentPiece = gameState[i, j];
if (currentPiece != Pieces.empty)
{
// if the current piece is mine
if (MyPiece(currentPiece))
{
// check if my piece is a king
if (currentPiece == Pieces.whiteKing || currentPiece == Pieces.blackKing)
stateValue += 80;
// my piece is a man
else
{
stateValue += 30;
// row values, closer to king zone higher the value
if (currentPiece == Pieces.blackMan)
{
// black goes in reverse direction
int y = 7-j;
stateValue += y;
}
else
stateValue += j;
}
// pieces on the edge are safe from capture
if (i == 0 ||i == 7 || j== 0 ||j ==7)
{
stateValue += 10;
}
}
// point reduction for enemy pieces
else
{
if (currentPiece == Pieces.whiteKing || currentPiece == Pieces.blackKing)
stateValue -= 80;
else
{
stateValue -= 20;
// row values, closer to king zone higher the value
if (currentPiece == Pieces.blackMan )
{
// black goes in reverse direction
int y = 7-j;
stateValue -= y;
}
else
stateValue -= j;
}
// pieces on the edge cant be captured
if (i == 0 || i == 7 || j == 0 || j == 7)
{
stateValue -= 10;
}
}
}
}
}
return stateValue;
}
First, I want to point out that your functions Maximizer and Minimizer can be combined in one function Minimax(Pieces, gameState, depth, bool is_maximizing) because their logic is almost the same except the couple of lines of code. So instead of calling Maximizer, you will call Minimax with is_maximizing set to true. And instead of calling Minimizer, just call Minimax with is_maximizing set to false. This will help to avoid repetition and will make your code more readable.
This first point leads us to a mistake in the algorithm. In the Minimize function you recursively call itself, while you should call the Maximize function.
Another point is the way you handle all valid moves in the given position. You don't have to separate processing of capture moves from non-capture ones. The reason is once again that the logic for processing both types of moves is the same. I suggest to create two functions - GenerateValidMoves() and SortValidMoves(). GenerateValidMoves() function will generate a list of all valid moves in the given position. After the moves list was generated, call SortValidMoves() to sort the list so that capture moves are located in the beginning of the list followed by non-capture moves.
Here is a simplified pseudocode for minimax:
Minimax(color, board, depth, is_max):
if ((depth == DEPTH_CUTOFF) or IsTerminalNode()):
return EvalBoard()
best_score = is_max ? -infinity : infinity
valid_moves = GenerateValidMoves(board, color)
for curr_move in valid_moves:
clone_board = board.clone()
clone_board.make_move(curr_move)
int curr_score = Minimax(opposite_color, clone_board, depth + 1, !is_max)
if (is_max) {
if (curr_score > best_score) {
best_score = curr_score
best_move = curr_move
}
} else {
if (curr_score < best_score) {
best_score = curr_score
best_move = curr_move
}
}
return best_score

2D Nearest Neighbor Search

Starting from the green square, I want an efficient algorithm to find the nearest 3 x 3 window with no red squares, only blue squares. The algorithm doesn't need to find exactly the closest 3 x 3 window, but it should find a 3 x 3 all-blue window close to the green square (assuming one exists). I thought about implementing this as a recursive breadth-first search, but that solution would involve re-checking the same square many times. Posting this to see if someone knows of a more efficient solution. Cost to check a given square is constant and cheap, but I want to minimize the execution time of the algorithm as much as possible (practical application of this will involve finding a 3x3 "clear" / all-blue window within a much larger 2D search area).
Here's an example solution, but I don't think it's optimal. It's actually a depth-first search that I will have to restructure to convert to a breadth-first, but I need to think a bit more about how to do that (one way would be to make each point an object that expands to neighboring points, then iterate multiple times across those points to children, visit those children before allowing those children to generate more children). Point is that I think there's a more efficient and common way to do this so I'm trying to avoid reinventing the wheel.
public class Search2D {
private TreeSet<Point> centerpointscheckedsofar;
private Point Search(Point centerpoint) {
if(centerpointscheckedsofar.contains(centerpoint)) {
return null;
}
if(isWithinBounds(centerpoint)) {
if(checkCenterPoint(centerpoint)) {
centerpointscheckedsofar.add(centerpoint);
return null;
}
Point result = Search(getPoint(-1, -1, centerpoint));
if(result != null) return result;
result = Search(getPoint(-1, 0, centerpoint));
if(result != null) return result;
result = Search(getPoint(-1, 1, centerpoint));
if(result != null) return result;
result = Search(getPoint(0, -1, centerpoint));
if(result != null) return result;
result = Search(getPoint(0, 1, centerpoint));
if(result != null) return result;
result = Search(getPoint(1, -1, centerpoint));
if(result != null) return result;
result = Search(getPoint(1, 0, centerpoint));
if(result != null) return result;
result = Search(getPoint(1, 1, centerpoint));
if(result != null) return result;
}
return null;
}
private Point getPoint(int x, int y, Point centerpoint) {
return new Point(centerpoint.x + x, centerpoint.y + y);
}
private boolean checkCenterPoint(Point centerpoint) {
//check here to see if point is valid
return false;
}
private boolean isWithinBounds(Point startPoint) {
//check here to see if point and all neighboring points of 3 x 3 window falls within bounds
return false;
}
}
UPDATE:
Distance measure is not that important, but for simplicity, let's minimize Manhattan distance.
Here's a better algorithm that does not use recursion and will be guaranteed to find the closest solution (or one of the closest solutions if there is a tie). It needs a grid greater than 5 x 5 to work properly, but if you want to search a grid smaller than that, there's probably a more efficient algorithm that can be used. Assumes lowest x-index is 0 and lowest y-index is also 0.
import java.awt.Point;
public class Search2D_v2 {
private boolean[][] bitgrid;
public Search2D_v2() {
bitgrid = new boolean[20][20];
}
public Point search(int centerx, int centery, int maxx, int maxy, int maxsearchsteps) {
//check starting point first, if it works, we're done
if(checkPoint(centerx, centery)) {
return new Point(centerx, centery);
}
int westbound = centerx-1;
boolean keepgoingwest = true;
int eastbound = centerx+1;
boolean keepgoingeast = true;
int southbound = centery-1;
boolean keepgoingsouth = true;
int northbound = centery+1;
boolean keepgoingnorth = true;
//stay within bounds, may move initial search square by 1 east and 1 west
if(westbound <= 0) {
eastbound = 3;
westbound = 1;
}
if(eastbound >= maxx) {
eastbound = maxx - 1;
westbound = maxx - 3;
}
if(southbound == 0) {
northbound = 3;
southbound = 1;
}
if(northbound == maxy) {
northbound = maxy - 1;
southbound = maxy - 3;
}
//always search boundary, we've already searched inside the boundary on previous iterations, expand boundary by 1 step / square for each iteration
for(int i = 0; i < maxsearchsteps && (keepgoingwest || keepgoingeast || keepgoingsouth || keepgoingnorth); i++) {
//search top row
if(keepgoingnorth) { //if we have already hit the north bound, stop searching the top row
for(int x = westbound; x <= eastbound; x++) {
if(checkPoint(x, northbound)) {
return new Point(x, northbound);
}
}
}
//search bottom row
if(keepgoingsouth) {
for(int x = westbound; x <= eastbound; x++) {
if(checkPoint(x, southbound)) {
return new Point(x, southbound);
}
}
}
//search westbound
if(keepgoingwest) {
for(int y = southbound; y <= northbound; y++) {
if(checkPoint(westbound, northbound)) {
return new Point(westbound, y);
}
}
}
//search eastbound
if(keepgoingeast) {
for(int y = southbound; y <= northbound; y++) {
if(checkPoint(eastbound, northbound)) {
return new Point(eastbound, y);
}
}
}
//expand search area by one square on each side
if(westbound - 2 >= 0) {
westbound--;
}
else {
keepgoingwest = false;
}
if(eastbound + 2 <= maxx) {
eastbound++;
}
else {
keepgoingeast = false;
}
if(southbound - 2 >= 0) {
southbound--;
}
else {
keepgoingsouth = false;
}
if(northbound + 2 <= maxy) {
northbound++;
}
else {
keepgoingnorth = false;
}
}
return null; //failed to find a point
}
private boolean checkPoint(int centerx, int centery) {
return !bitgrid[centerx][centery] && //center
!bitgrid[centerx-1][centery-1] && //left lower
!bitgrid[centerx-1][centery] && //left middle
!bitgrid[centerx-1][centery+1] && //left upper
!bitgrid[centerx][centery-1] && //middle lower
!bitgrid[centerx][centery+1] && //middle upper
!bitgrid[centerx+1][centery-1] && //right lower
!bitgrid[centerx+1][centery] && //right middle
!bitgrid[centerx+1][centery+1]; //right upper
}
}
A simple advice would be to mark all the cells you have checked. That way you won't have to check the cells multiple times.
Recursion will definitely take more time than an iteration based approach since it will create a new stack each time you make a new call. If you are trying to find the closest one, prefer BFS over DFS.
I would also suggest making a quick internet research for "Flood Fill Algorithm".
You could spiral outwards from your starting pixel. Whenever you encounter a pixel p that has not been checked, examine the 3x3 environment around p.
For each red pixel r in the environment set the 3x3 environment of r to checked.
If there was no red pixel in the environment you found a solution.
What you're trying to find in a more general sense is a kind of morphological filter of your array.
We can define the filter as a 3x3 sliding window which sets the center of the window to the sum of the array elements within the window. Let blue squares be represented by 1 and red squares be represented by 0.
In this situation, you're trying to find the closest element with a sum value of 9.
Note that one way of solving this problem is slide a 3x3 window across your array so that it covers all possible locations. In this case, you would look at 9*width*height elements. You could then find the nearest sum value of 9 using a breadth-first search in, at most, width*height checks. So the naive time of your algorithm is proportional to 10*width*height
You can reduce this by ensuring that your filter only has to look at one value per focal cell, rather than 9. To do so, generate a summed-area table. Now your time is proportional to 2*width*height.
An example of a summed-area table
You can might be able to make this faster. Each time you find a value of 9, compare it against the location of your green cell at that moment. If most cells are not 9s, this reduces your time to some proportional to width*height.
Hensley et al. (2005)'s paper Fast Summed-Area Table Generation and its Applications explains how to use graphics hardware to generate the summed-area table in O(log n) time. So it's possible to really reduce run-times on this. Nehab et al. (2011)'s paper GPU-efficient recursive filtering and summed-area tables might also be useful (source code): their work suggests that for small windows, such as yours, the direct approach may be most efficient.
I think the easiest way is to use a slightly modified breadth-first search.
If we talk about Manhattan distance, then each square will have maximum 4 neighbors. On each step we check if the number of neighbors is equal to 3 (the fourth neighbor is a square we came from). If so, we check diagonals. Else - continue search.
public class Field3x3 {
private static class Point {
int x, y, distance;
Point previous;
public Point(int x, int y) {
this.x = x;
this.y = y;
this.distance = 0;
this.previous = this;
}
public Point(int x, int y, Point previous) {
this.x = x;
this.y = y;
this.previous = previous;
this.distance = previous.distance + 1;
}
#Override
public String toString() {
return "{x: " + x +", y: " + y + ", distance:" + distance +'}';
}
}
private static Point traverse(int[][] field, int x, int y) {
int i = 0;
Queue<Point> q = new LinkedList<>();
q.add(new Point(x, y));
while (!q.isEmpty()) {
Point p = q.remove();
System.out.print(i++ + ". current: " + p);
if (field[p.y][p.x] == 1) {
field[p.y][p.x] = 2;
List<Point> neighbors = getNeighbors(p, field);
System.out.println(", neighbors: " + neighbors);
if (neighbors.size() == 3 && checkDiagonals(p, field)) return p;
for (Point neighbor : neighbors) {
if (field[neighbor.y][neighbor.x] == 1) {
q.add(neighbor);
}
}
} else System.out.println(", already visited");
}
return null;
}
private static boolean checkDiagonals(Point p, int[][] field) {
return field[p.y - 1][p.x - 1] > 0 && field[p.y + 1][p.x - 1] > 0
&& field[p.y - 1][p.x + 1] > 0 && field[p.y + 1][p.x + 1] > 0;
}
private static List<Point> getNeighbors(Point p, int[][] field) {
List<Point> neighbors = new ArrayList<>();
if (p.y > 0 && field[p.y - 1][p.x] > 0 && p.y <= p.previous.y)
neighbors.add(new Point(p.x, p.y - 1, p));
if (p.y < field.length - 1 && field[p.y + 1][p.x] > 0 && p.y >= p.previous.y)
neighbors.add(new Point(p.x, p.y + 1, p));
if (p.x > 0 && field[p.y][p.x - 1] > 0 && p.x <= p.previous.x)
neighbors.add(new Point(p.x - 1, p.y, p));
if (p.x < field[p.y].length - 1 && field[p.y][p.x + 1] > 0 && p.x >= p.previous.x)
neighbors.add(new Point(p.x + 1, p.y, p));
return neighbors;
}
public static void main(String[] args){
int[][] field = {{1,0,0,1,1,0,1,1,1},
{1,1,1,1,1,1,1,0,1},
{1,1,1,0,1,0,1,1,1},
{0,1,1,1,1,1,1,1,0},
{1,1,1,0,0,1,1,1,0},
{1,0,1,1,1,1,0,1,0},
{1,1,1,1,0,1,1,1,0},
{1,1,1,0,1,1,1,1,0},
{1,1,1,1,0,1,1,1,0}};
System.out.println("Answer: " + traverse(field, 1, 2));
}
}

Computing next prefix index in KMP implementations

I've read through a number of different implementations of KMP and can't quite figure out one aspect they all share.
When they compute the longest prefix which is also suffix-array (lps).
If the characters do not match at the indexes tested at a specific iteration, and the index of the prefix is not 0. The index of the prefix is set to
index = lps[index - 1];
Here is an example
void computeLPSArray(String pat, int M, int lps[])
{
// length of the previous longest prefix suffix
int len = 0;
int i = 1;
lps[0] = 0; // lps[0] is always 0
// the loop calculates lps[i] for i = 1 to M-1
while (i < M)
{
if (pat.charAt(i) == pat.charAt(len))
{
len++;
lps[i] = len;
i++;
}
else // (pat[i] != pat[len])
{
// This is tricky. Consider the example.
// AAACAAAA and i = 7. The idea is similar
// to search step.
if (len != 0)
{
len = lps[len-1];
// Also, note that we do not increment
// i here
}
else // if (len == 0)
{
lps[i] = len;
i++;
}
}
}
}
Is there any situation where index = lps[index-1] is not equivalent to
index--;

Range search in d-space with discrete coordinates

I would like to develop a range searching algorithm that reports all points within a given distance of a query point.
The points are specified by d integer coordinates in a tiny range, say up to 6 bits per dimension (range 0..63), for a total bit count not exceeding 60 bits.
The distance metric is Manhattan or Euclidean (up to you), i.e. the sum of absolute or squared coordinate differences. In the special case of a single bit per dimension, it amounts to the Hamming distance.
There can be up to a million points.
Are you aware of a practical data structure that supports fast queries, say O(LogĀ²(n)+k) or similar (with space O(n)) in such conditions ? A reasonable preprocessing time (subquadratic) is also required.
k-D trees are a first option, but they don't exploit the finiteness of the coordinates and are likely to perform poorly in high dimensions, I am afraid.
The case of a single bit per coordinate is especially interesting. Even partial solutions are welcome.
After some thought (and prodding by #YvesDaoust) using a VP Tree (Vantage Point Tree https://en.wikipedia.org/wiki/Vantage-point_tree) is probably the best solution.
VP Tree is a BSP where the left nodes are inside the distance and the right nodes are outside of the distance. This works for single bit per dimension and multiple bit per dimension (only the distance formula would change. The distance is a per tree node threshold/radius. Querying involves recursing through the tree getting current node value's distance to the query value and comparing that result with the query distance.
JSFiddle http://jsfiddle.net/fgq1rfLk/
var DIMS = 16;
var BITS = 1;
var MASK = (Math.pow(2, BITS) - 1)|0;
var SIZE = DIMS * BITS;
var list = [];
var tree = null;
//
// set bit count (population count)
function popCnt(x) {
x = x - ((x >> 1) & 0x55555555);
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
x = (x + (x >> 4)) & 0x0F0F0F0F;
x = x + (x >> 8);
x = x + (x >> 16);
return x & 0x0000003F;
}
//
// manhattan distance
function dist(a, b) {
if(BITS == 1) {
return popCnt(a ^ b);
}
var result = 0;
for(var i=0; i<DIMS; i++) {
var shr = i * BITS;
result += Math.abs(((a >> shr) & MASK) - ((b >> shr) & MASK));
}
return result;
}
//
// Vantage point tree
// max size of tree leaf nodes
VP_LEAF_SIZE = 32;
// need to choose a reasonable maximum distance
VP_DISTANCE = (BITS === 1) ? SIZE : 32;
function VPTree(data) {
this.radius = null;
this.center = null;
this.values = null;
this.inside = null;
this.outside = null;
//
var n = data.length;
var r = data[0];
// leaf node?
if(n <= VP_LEAF_SIZE || n <= 1) {
this.values = [].concat(data);
return this;
}
this.center = r;
// process data for counts at all possible distances
var buckets = Array(VP_DISTANCE + 1);
for(var i=0; i<=VP_DISTANCE; i++) {
buckets[i] = 0;
}
// distance counts
for(var i=0; i<n; i++) {
var v = data[i];
var d = dist(r, v);
if(d < VP_DISTANCE) {
buckets[d]++;
} else {
buckets[VP_DISTANCE]++;
}
}
// distance offsets
var sum = 0;
for(var i=0; i<=VP_DISTANCE; i++) {
buckets[i] = (sum += buckets[i]);
}
// pivot index
var median = n >> 1;
var pivot = 1;
for(var i=1; i<=VP_DISTANCE; i++) {
if(buckets[i] > median) {
pivot = (i > 1 && median - buckets[i - 1] <= buckets[i] - median) ? i - 1 : i;
break;
}
}
this.radius = pivot;
// parition data into inside and outside
var iCount = buckets[pivot] - buckets[0];
var oCount = (n - buckets[pivot]) - buckets[0];
var iData = Array(iCount);
var oData = Array(oCount);
iCount = oCount = 0;
for(var i=0; i<n; i++) {
var v = data[i];
if(v === r) { continue; };
if(dist(r, v) <= pivot) {
iData[iCount++] = v;
} else {
oData[oCount++] = v;
}
}
// recursively create the rest of the tree
if(iCount > 0) {
this.inside = new VPTree(iData);
}
if(oCount > 0) {
this.outside = new VPTree(oData);
}
return this;
}
VPTree.prototype.query = function(value, distance, result) {
if(result === undefined) {
return this.query(value, distance, []);
}
// leaf node, test all values
if(this.values !== null) {
for(var i=0; i<this.values.length; i++) {
var v = this.values[i];
if(dist(value, v) <= distance) {
result.push(v);
}
}
return result;
}
// recursively test the rest of the tree
var tmpDistance = dist(value, this.center);
// inside
if(tmpDistance <= distance + this.radius) {
if(tmpDistance <= distance) {
result.push(this.center);
}
if(this.inside !== null) {
this.inside.query(value, distance, result);
}
}
// outside
if(tmpDistance + distance > this.radius && this.outside !== null) {
this.outside.query(value, distance, result);
}
return result;
}
EDIT Here's the JSFiddle showing a 2d (x, y) (8bits, 8bits) http://jsfiddle.net/fgq1rfLk/1/
If the points have explicit coordinates and if d is not too large, which seems to be the case here, I think (but I may be wrong, needs testing) that a Kd-tree will be more efficient than a VP-tree, since it can benefit from more structure from the data (coordinates), whereas VP-tree only "sees" point-to-point distances.
There is an efficient implementation of Kd-trees with all the needed range search functions (L2 and Manathan metric) in ANN [1] (however, it stores all coordinates explicitly and you probably want to benefit from your "compressed coordinates" representation.
An alternative is my own implementation of KdTree in Geogram [2], it is quite simple (though highly inspired by ANN) and can probably quite easily be adapted to use your compressed coordinates representation (but it only has k nearest neighbors search with L2 metric)
Referencecs:
[1] https://www.cs.umd.edu/~mount/ANN/
[2] http://alice.loria.fr/software/geogram/doc/html/classGEO_1_1KdTree.html

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))

Resources