How BFS find the minimum path in maze solver - algorithm

I'm stuck at the solution of a problem.
Problem =>
You are given a square grid with some cells open (.) and some blocked (X). Your playing piece can move along any row or column until it reaches the edge of the grid or a blocked cell. Given a grid, a start and a goal, determine the minimum number of moves to get to the goal.
Example =>
...
.X.
...
The starting position (0,0) so start in the top left corner. The goal is (1,2) The path is (0,0)->(0,2)->(1,2). It takes moves to reach the goal.
Output = 2
Solution=>
BFS using Queue.
But how BFS can get to the minimum path for example if there is more than one path exist between starting and ending point then how BFS can get to the minimum one ?
Here is my solution for the above problem. But it doesn't work.
class Pair{
int x,y;
Pair(int a,int b){x=a;y=b;}
}
class Result {
public static int minimumMoves(List<String> grid, int startX, int startY, int goalX, int goalY)
{
int n=grid.get(0).length();
ArrayDeque<Pair> q=new ArrayDeque<Pair>();
Pair location[][]=new Pair[n][n];
char color[][]=new char[n][n];
//default color a mean it is neither in queue nor explore
//till now, b mean it is in queue, c means it already explore
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
color[i][j]='a';
}
}
q.addLast(new Pair(startX,startY));
int tempx,tempy,tempi,tempj;
while(!q.isEmpty()){
tempx=q.peekFirst().x;
tempy=q.peekFirst().y;
q.removeFirst();
color[tempx][tempy]='c';
tempj=tempy-1;
tempi=tempx;
//cheking unvisited node around -X axis
while(tempj>=0){
if(color[tempi][tempj]!='a' || grid.get(tempi).charAt(tempj)!='.'){
break;
}
q.addLast(new Pair(tempi,tempj));
color[tempi][tempj]='b';
location[tempi][tempj]=new Pair(tempx,tempy);
tempj--;
}
//checking unvisited node around +X axis
tempi=tempx;
tempj=tempy+1;
while(tempj<n){
if(color[tempi][tempj]!='a' || grid.get(tempi).charAt(tempj)!='.'){
break;
}
q.addLast(new Pair(tempi,tempj));
color[tempi][tempj]='b';
location[tempi][tempj]=new Pair(tempx,tempy);
tempj++;
}
//checking unvisited node around +Y axis
tempi=tempx-1;
tempj=tempy;
while(tempi>=0){
if(color[tempi][tempj]!='a' || grid.get(tempi).charAt(tempj)!='.'){
break;
}
q.addLast(new Pair(tempi,tempj));
color[tempi][tempj]='b';
location[tempi][tempj]=new Pair(tempx,tempy);
tempi--;
}
checking unvisited node around -Y axis
tempi=tempx+1;
tempj=tempy;
while(tempi<n){
if(color[tempi][tempj]!='a' || grid.get(tempi).charAt(tempj)!='.'){
break;
}
q.addLast(new Pair(tempi,tempj));
color[tempi][tempj]='b';
location[tempi][tempj]=new Pair(tempx,tempy);
tempi++;
}
}//end of main while
//for track the path
Stack<Pair> stack=new Stack<Pair>();
//If path doesn't exist
if(location[goalX][goalY]==null){
return -1;
}
boolean move=true;
stack.push(new Pair(goalX,goalY));
while(move){
tempi=stack.peek().x;
tempj=stack.peek().y;
stack.push(location[tempi][tempj]);
if(tempi==startX && tempj==startY){
move=false;
}
}
System.out.println(stack);
return stack.size()-2;
}
}
Here My algorithm only find the path. Not the minimum path. Can anyone suggest me how BFS finds the minimum path here and what should I change into my code ?

BFS finds the minimal path by concentric moving outward, so everything in round 1 is 1 away from start, all squares added there are then 2 away from start and so on. This means the basic idea of using BFS to find the path is good, unfortunately the implementation is a bit difficult and slow.
Another way of viewing it is to think about the grid as a graph, with all squares connected to all other squares up, down, left and right until they hit the edge or an obstacle.
A third way of thinking of it is like a flood fill, first round only start is filled, next round all that can be accessed from it is filled and so on.
The major thing is that you break when you see a b.
aabbaaaaaa
aabbbaaaaa
babbbaaaaa
babbbaaaaa
babbbaaaaa
babbbaaaaa
bbbbbaaaaa
bbbbbaaaaa
bCbbbAAAAA
cccccaaaaa
When processing the capital Cit stops because it is surrounded by bs and cs. And therefore you don't examine the As.
I have hacked the code a bit, note i'm not a java programmer ... my main problem when trying to solve it was timeouts. I believe this can be solved without the location array by recording how many generations of BFS we run, that should save a lot of memory and time.
class Pair{
int x,y;
Pair(int a,int b){x=a;y=b;}
public String toString() {
return "[" + x + "," + y + "]";
}
}
class Result {
/*
* Complete the 'minimumMoves' function below.
*
* The function is expected to return an INTEGER.
* The function accepts following parameters:
* 1. STRING_ARRAY grid
* 2. INTEGER startX
* 3. INTEGER startY
* 4. INTEGER goalX
* 5. INTEGER goalY
*/
public static int minimumMoves(List<String> grid, int startX, int startY, int goalX, int goalY) {
if (startX==goalX&&startY==goalY)
return 0;
startX += 1;
startY += 1;
goalX += 1;
goalY += 1;
int n=grid.get(0).length();
Pair dirs[] = {new Pair(-1,0), new Pair(+1,0), new Pair(0,-1), new Pair(0,+1)};
ArrayDeque<Pair> q=new ArrayDeque<Pair>();
Pair location[][]=new Pair[n+2][n+2];
char color[][]=new char[n+2][n+2];
//default color a mean it is neither in queue nor explore
//till now, b mean it is in queue, c means it already explore
for(int i=0;i<n+2;i++){
for(int j=0;j<n+2;j++){
if (i == 0 || i == n+1 ||j == 0 || j == n+1 || // boarder
grid.get(i-1).charAt(j-1)!='.')
color[i][j]='x';
else
color[i][j]='a';
}
}
q.addLast(new Pair(startX,startY));
int tempx,tempy,tempi,tempj;
while(!q.isEmpty()){
tempx=q.peekFirst().x;
tempy=q.peekFirst().y;
q.removeFirst();
if(location[goalX][goalY]!=null){
System.out.println("Goal reached");
break;
}
color[tempx][tempy]='c';
for (Pair dir : dirs ) {
tempi=tempx;
tempj=tempy;
while(true){
tempi+=dir.x;
tempj+=dir.y;
if (color[tempi][tempj]=='x') { // includes boarder
break;
}
if (color[tempi][tempj]>='b') {
continue;
}
q.addLast(new Pair(tempi,tempj));
color[tempi][tempj]='b';
location[tempi][tempj]=new Pair(tempx,tempy);
}
}
// System.out.println(location[goalX][goalY]);
// for(int i = 1; i < n+1; i++) {
// for(int j = 1; j < n+1; j++) {
// System.out.printf("%c", color[i][j]);
// }
// System.out.println();
// }
}//end of main while
//for track the path
Stack<Pair> stack=new Stack<Pair>();
//If path doesn't exist
if(location[goalX][goalY]==null){
System.out.printf("Gaol not reached %d %d", goalX, goalY);
System.out.println();
for(int i = 1; i < n+1; i++) {
for(int j = 1; j < n+1; j++) {
System.out.printf("%s", location[i][j]);
}
System.out.println();
}
return -1;
}
boolean move=true;
int moves = 0;
tempi = goalX;
tempj = goalY;
while(move){
System.out.println(String.valueOf(tempi)+" "+ String.valueOf(tempj));
moves = moves +1;
Pair cur = location[tempi][tempj];
tempi=cur.x;
tempj=cur.y;
if(tempi==startX && tempj==startY){
move=false;
}
}
System.out.println(moves);
return moves;
}
}

Related

Find the maximum height they can make by standing on each other?

Weights of n men and their strengths (max weight they can carry) are given. Height of all are same and given. Find the maximum height they can make by standing on each other?
That means, you have to place them by taking maximum number of men from them, such that no men is carrying weight more than his strength.
This question is bugging me. First I thought using greedy, by taking person of maximum strength first, but it is not giving correct answer. Then I tried to solve it, like knapsack, which is also not right. I am not able to come up with an efficient algorithm. Can anyone help?
First of all sorry by my english :)
Here is one way that you can think as a way to solve the problem.
Ok if you can supposed that each floor absorbs the whole weight in a uniform form, ( I mean there are no restriction like "one man can carry only the weight of two mens" or somethin like that..).
We will start with an hypothetical structure which has one man for each floor, and with that structure we will start to check the restrictions and arrange people.
We will check the lowest floor (first floor), and we will ask: Can this floor handle the weight of all the higher floors?
If the answer is no, we remove one men from the top of the tower and we add it to this floor, and we check again the weight condition on this floor.
If the answer is yes, we pass to check the next floor.
After that we will have an structure which meet the requirements.
And the C# code:
int amountOfMens = n;
float weight = w;
float strength = s;
float height = h;
int []mensInEachFloor;
public void MyAlg()
{
mensInEachFloor = new int[ amountOfMens ]; // the max height that we can achieve is the max amount of mens.
for(int i=0; i < mensInEachFloor.Length; i++ )
{
// we put one men on each floor, just to check if the highest heigth is achivable
mensInEachFloor[i] = 1;
}
// now we start to use our algorithm
// for each floor:
for(int i = 0; i < mensInEachFloor.Length; i++ )
{
// for each floor we will work on it until supports its designed weight
bool floorOk = false;
while(! floorOk)
{
// we check if the weigth of all the higher floors can be supported by this level
float weightToBeSupported = TotalWeightOfHigherFloors(i+1);
float weightThatCanBeSupported = WeightHandledByFloor(i);
if( weightToBeSupported > weightThatCanBeSupported )
{
// Remove one men from the top
RemoveOneManFromHighestFloor();
// add one men to this floor to help with the weight
AddOneManToFloor(i);
}
else
{
// we are ok on this floor :)
floorOk = true;
}
}
}
Debug.Log("The total heigth of the tower is : " + GetTowerHeight() );
}
private float TotalWeightOfHigherFloors(int startingFloor)
{
float totalWeight = 0;
for(int i= startingFloor; i< mensInEachFloor.Length; i++ )
{
totalWeight += mensInEachFloor[i] * weight;
}
return totalWeight;
}
private float WeightHandledByFloor(int floor)
{
return mensInEachFloor[floor] * strength;
}
private void RemoveOneManFromHighestFloor()
{
// we start to see from the top..
for(int i = mensInEachFloor.Length - 1 ; i >= 0; i-- )
{
// if on this floor are one or more mens..
if(mensInEachFloor[i] != 0)
{
// we remove from the floor
mensInEachFloor[i] = mensInEachFloor[i] - 1;
// and we are done
break;
}
}
}
private void AddOneManToFloor(int floor)
{
// Add one man to the selected floor
mensInEachFloor[floor] = mensInEachFloor[floor] + 1;
}
private float GetTowerHeight()
{
// We will count the number of floors with mens on it
float amountOfFloors = 0;
for(int i= 0; i< mensInEachFloor.Length; i++ )
{
// If there are more than zero mens
if( mensInEachFloor[i] > 0 )
{
// it means that it is a valid floor
amountOfFloors++;
}
}
// number of floors times height
return amountOfFloors * height;
}
Cheers !

traverse all edges and print nodes in euler circuit

I am trying to solve this question.
I am able to find by seeing the degrees that the given structure can form euler circuit or not but I am unable to figure out how to find trace all path, for the given test case
5
2 1
2 2
3 4
3 1
2 4
there is one loop in the circuit at node 2, which I don't know how to trace, If I am using adjacency list representation then I'll get following list
1: 2,3
2: 1,2,2,4
3: 1,4
4: 2,3
So how to traverse every edge, I know it is euler circuit problem, but that self loop thing is making tough for me to code and I am not getting any tutorial or blog from where I can understand this thing.
I again thought to delete the nodes from adjacency list once I traverse that path( in order to maintain the property of euler(path should be traversed once)), but I am using vector for storing adjacency list and I don't know how to delete particular element from vector. I googled it and found remove command to delete from vectors but remove deletes all matching element from the vector.
I tried to solve the problem as below now, but getting WA :(
#include<iostream>
#include<cstdio>
#include<cstring>
int G[52][52];
int visited[52],n;
void printadj() {
int i,j;
for(i=0;i<51;i++) {
for(j=0;j<51;j++)
printf("%d ",G[i][j]);
printf("\n");
}
}
void dfs(int u){
int v;
for(v=0;v<51;v++){
if(G[u][v]){
G[u][v]--;
G[v][u]--;
printf("%d %d\n",u,v);
dfs(v);
}
}
}
bool is_euler(){
int i,j,colsum=0,count=0;
for(i=0;i<51;i++) {
colsum=0;
for(j=0;j<51;j++) {
if(G[i][j] > 0) {
colsum+=G[i][j];
}
}
if(colsum%2!=0) count++;
}
// printf("\ncount=%d\n",count);
if(count >0 ) return false;
else return true;
}
void reset(){
int i,j;
for(i=0;i<51;i++)
for(j=0;j<51;j++)
G[i][j]=0;
}
int main(){
int u,v,i,t,k;
scanf("%d",&t);
for(k=0;k<t;k++) {
scanf("%d",&n);
reset();
for(i=0;i<n;i++){
scanf("%d%d",&u,&v);
G[u][v]++;
G[v][u]++;
}
// printadj();
printf("Case #%d\n",k+1);
if(is_euler()) {
dfs(u);
}
else printf("some beads may be lost\n");
printf("\n");
}
return 0;
}
Dont know why getting WA :(
New Code:-
#include<iostream>
#include<cstdio>
#include<cstring>
#define max 51
int G[max][max],print_u[max],print_v[max],nodes_traversed[max],nodes_found[max];
int n,m;
void printadj() {
int i,j;
for(i=0;i<max;i++) {
for(j=0;j<max;j++)
printf("%d ",G[i][j]);
printf("\n");
}
}
void dfs(int u){
int v;
for(v=0;v<50;v++){
if(G[u][v]){
G[u][v]--;
G[v][u]--;
print_u[m]=u;
print_v[m]=v;
m++;
dfs(v);
}
}
nodes_traversed[u]=1;
}
bool is_evendeg(){
int i,j,colsum=0,count=0;
for(i=0;i<50;i++) {
colsum=0;
for(j=0;j<50;j++) {
if(G[i][j] > 0) {
colsum+=G[i][j];
}
}
if(colsum&1) return false;
}
return true;
}
int count_vertices(int nodes[]){
int i,count=0;
for(i=0;i<51;i++) if(nodes[i]==1) count++;
return count;
}
void reset(){
int i,j;
m=0;
for(i=0;i<max;i++)
for(j=0;j<max;j++)
G[i][j]=0;
memset(print_u,0,sizeof(print_u));
memset(print_v,0,sizeof(print_v));
memset(nodes_traversed,0,sizeof(nodes_traversed));
memset(nodes_found,0,sizeof(nodes_found));
}
bool is_connected(int tot_nodes,int trav_nodes) {
if(tot_nodes == trav_nodes) return true;
else return false;
}
int main(){
int u,v,i,t,k,tot_nodes,trav_nodes;
scanf("%d",&t);
for(k=0;k<t;k++) {
scanf("%d",&n);
reset();
for(i=0;i<n;i++){
scanf("%d%d",&u,&v);
G[u][v]++;
G[v][u]++;
nodes_found[u]=nodes_found[v]=1;
}
// printadj();
printf("Case #%d\n",k+1);
tot_nodes=count_vertices(nodes_found);
if(is_evendeg()) {
dfs(u);
trav_nodes=count_vertices(nodes_traversed);
if(is_connected(tot_nodes,trav_nodes)) {
for(i=0;i<m;i++)
printf("%d %d\n",print_u[i],print_v[i]);
}
else printf("some beads may be lost\n");
}
else printf("some beads may be lost\n");
printf("\n");
}
return 0;
}
This code is giving me runtime error there, please look into the code.
What you need to do is form arbitrary cycles and then connect all cycles together. You seem to be doing only one depth first traversal, which might give you a Eulerian circuit, but it also may give you a 'shortcut' of an Eulerian circuit. That is because in every vertex where the Eulerian circuit passes more then once (i.e., where it crosses itself), when the depth first traversal arrives there for the first time, it may pick the edge that leads directly back to the start of the depth first traversal.
Thus, you're algorithm should consist of two parts:
Find all cycles
Connect the cycles together
If done right, you don't even have to check that all vertices have an even degree, instead you can rely on the fact that if step 1 or 2 cannot continue anymore, there exists no Eulerian cycle.
Reference Implementation (Java)
Since there's no language tag in your question, I'm going to assume that it's fine for you that I'll give you a Java reference implementation. Furthermore, I'll use the term 'node' instead of 'vertex', but that's just personal preference (it gives shorter code ;)).
I'll use one constant in this algorithm, which I will refer to from the other classes:
public static final int NUMBER_OF_NODES = 50;
Then, we'll need an Edge class to easily construct our cycles, which are basically linked lists of edges:
public class Edge
{
int u, v;
Edge prev, next;
public Edge(int u, int v)
{
this.u = u;
this.v = v;
}
/**
* Attaches a new edge to this edge, leading to the given node
* and returns the newly created Edge. The node where the
* attached edge starts doesn't need to be given, as it will
* always be the node where this edge ends.
*
* #param node The node where the attached edge ends.
*/
public Edge attach(int node)
{
next = new Edge(this.v, node);
next.prev = this;
return next;
}
}
Then, we'll need a Cycle class that can easily join two cycles:
public class Cycle
{
Edge start;
boolean[] used = new boolean[NUMBER_OF_NODES+1];
public Cycle(Edge start)
{
// Store the cycle itself
this.start = start;
// And memorize which nodes are being used in this cycle
used[start.u] = true;
for (Edge e = start.next; e != start; e = e.next)
used[e.u] = true;
}
/**
* Checks if this cycle can join with the given cycle. That is
* the case if and only if both cycles use a common node.
*
* #return {#code true} if this and that cycle can be joined,
* {#code false} otherwise.
*/
public boolean canJoin(Cycle that)
{
// Find a commonly used node
for (int node = 1; node <= NUMBER_OF_NODES; node++)
if (this.used[node] && that.used[node])
return true;
return false;
}
/**
* Joins the given cycle to this cycle. Both cycles will be broken
* at a common node and the paths will then be connected to each
* other. The given cycle should not be used after this call, as the
* list of used nodes is most probably invalidated, only this cycle
* will be updated and remains valid.
*
* #param that The cycle to be joined to this cycle.
*/
public void join(Cycle that)
{
// Find the node where we'll join the two cycles
int junction = 1;
while (!this.used[junction] || !that.used[junction])
junction++;
// Find the join place in this cycle
Edge joinAfterEdge = this.start;
while (joinAfterEdge.v != junction)
joinAfterEdge = joinAfterEdge.next;
// Find the join place in that cycle
Edge joinBeforeEdge = that.start;
while (joinBeforeEdge.u != junction)
joinBeforeEdge = joinBeforeEdge.next;
// Connect them together
joinAfterEdge.next.prev = joinBeforeEdge.prev;
joinBeforeEdge.prev.next = joinAfterEdge.next;
joinAfterEdge.next = joinBeforeEdge;
joinBeforeEdge.prev = joinAfterEdge;
// Update the used nodes
for (int node = 1; node <= NUMBER_OF_NODES; node++)
this.used[node] |= that.used[node];
}
#Override
public String toString()
{
StringBuilder s = new StringBuilder();
s.append(start.u).append(" ").append(start.v);
for (Edge curr = start.next; curr != start; curr = curr.next)
s.append("\n").append(curr.u).append(" ").append(curr.v);
return s.toString();
}
}
Now our utility classes are in place, we can write the actual algorithm (although technically, part of the algorithm is extending a path (Edge.attach(int node)) and joining two cycles (Cycle.join(Cycle that)).
/**
* #param edges A variant of an adjacency matrix: the number in edges[i][j]
* indicates how many links there are between node i and node j. Note
* that this means that every edge contributes two times in this
* matrix: one time from i to j and one time from j to i. This is
* also true in the case of a loop: the link still contributes in two
* ways, from i to j and from j to i, even though i == j.
*/
public static Cycle solve(int[][] edges)
{
Deque<Cycle> cycles = new LinkedList<Cycle>();
// First, find a place where we can start a new cycle
for (int u = 1; u <= NUMBER_OF_NODES; u++)
for (int v = 1; v <= NUMBER_OF_NODES; v++)
if (edges[u][v] > 0)
{
// The new cycle starts at the edge from u to v
Edge first, last = first = new Edge(u, v);
edges[last.u][last.v]--;
edges[last.v][last.u]--;
int curr = last.v;
// Extend the list of edges until we're back at the start
search: while (curr != u)
{
// Find any edge that extends the last edge
for (int next = 1; next <= NUMBER_OF_NODES; next++)
if (edges[curr][next] > 0)
{
// We found an edge, attach it to the last one
last = last.attach(next);
edges[last.u][last.v]--;
edges[last.v][last.u]--;
curr = next;
continue search;
}
// We can't form a cycle anymore, which
// means there is no Eulerian cycle.
return null;
}
// Connect the end to the start
last.next = first;
first.prev = last;
// Save it
cycles.add(new Cycle(last));
// And don't forget about the possibility that there are
// more edges running from u to v, so v should be
// re-examined in the next iteration.
v--;
}
// Now we have put all edges into cycles,
// we join them all together (if possible)
merge: while (cycles.size() > 1)
{
// Join the last cycle with any of the previous ones
Cycle last = cycles.removeLast();
for (Cycle curr : cycles)
if (curr.canJoin(last))
{
// Found one! Just join it and continue the merge
curr.join(last);
continue merge;
}
// No compatible cycle found, meaning there is no Eulerian cycle
return null;
}
return cycles.getFirst();
}

How to find pair edge while building half-edge data structure

I cannot find out an efficient way to generate the opposite edges of a given edge. My idea is just to do the iterates:
//construct the opposite half edges
for(int j=0;j<edge_num;j++)
for(int m=0;m<edge_num;m++)
if(edge[j].vert_end->v_index==edge[m].vert_start->v_index &&
edge[j].vert_start->v_index==edge[m].vert_end->v_index )
{
edge[j].pair = &edge[m];
edge[m].pair = &edge[j];
}
Other information about an half edge is generated from the procedure of loading .M file.
My structure is:
class HE_vert{
public:
GLfloat x, y, z;
int v_index;
HE_edge *edge;
};
class HE_face{
public:
int v1, v2, v3;
int f_index;
HE_edge* edge;
};
class HE_edge{
public:
HE_edge(){ pair = NULL; }
public:
HE_vert* vert_start; // vertex at the start of the half-edge
HE_vert* vert_end; // vertex at the end of the half-edge
HE_edge* pair; // oppositely oriented adjacent half-edge
HE_face* face; // face the half-edge borders
HE_edge* next; // next half-edge around the face
int e_index;
};
I checked all the output information and it’s correct, but it took a long computational time, especially when loading bunny.M. How can I do this in an more efficient way? Could you give me some hints?
// grid[i + vert_num*j] = edge from i to j
int grid[vert_num*vert_num]; // malloc()?
// memset()?
for (int i = vert_num*vert_num - 1; i >= 0; i--)
{
grid[i] = -1;
}
for (int i = 0; i < edge_num; i++)
{
int i_from = edge[i]->vert_start->v_index;
int i_to = edge[i]->vert_end->v_index;
int pair_index = grid[i_to + vert_num*i_from];
if (pair_index >= 0)
{
edge[i]->pair = edge[pair_index];
edge[pair_index]->pair = edge[i];
grid[i_to + vert_num*i_from] = -1;
}
else
{
grid[i_from + vert_num*i_to] = i;
}
}
Possible optimization: Use a linked list instead of a huge array. There will only be about 1-4 entries for each row/column.

Cycle finding algorithm

I need do find a cycle beginning and ending at given point. It is not guaranteed that it exists.
I use bool[,] points to indicate which point can be in cycle. Poins can be only on grid. points indicates if given point on grid can be in cycle.
I need to find this cycle using as minimum number of points.
One point can be used only once.
Connection can be only vertical or horizontal.
Let this be our points (red is starting point):
removing dead ImageShack links
I realized that I can do this:
while(numberOfPointsChanged)
{
//remove points that are alone in row or column
}
So i have:
removing dead ImageShack links
Now, I can find the path.
removing dead ImageShack links
But what if there are points that are not deleted by this loop but should not be in path?
I have written code:
class MyPoint
{
public int X { get; set; }
public int Y { get; set; }
public List<MyPoint> Neighbours = new List<MyPoint>();
public MyPoint parent = null;
public bool marked = false;
}
private static MyPoint LoopSearch2(bool[,] mask, int supIndexStart, int recIndexStart)
{
List<MyPoint> points = new List<MyPoint>();
//here begins translation bool[,] to list of points
points.Add(new MyPoint { X = recIndexStart, Y = supIndexStart });
for (int i = 0; i < mask.GetLength(0); i++)
{
for (int j = 0; j < mask.GetLength(1); j++)
{
if (mask[i, j])
{
points.Add(new MyPoint { X = j, Y = i });
}
}
}
for (int i = 0; i < points.Count; i++)
{
for (int j = 0; j < points.Count; j++)
{
if (i != j)
{
if (points[i].X == points[j].X || points[i].Y == points[j].Y)
{
points[i].Neighbours.Add(points[j]);
}
}
}
}
//end of translating
List<MyPoint> queue = new List<MyPoint>();
MyPoint start = (points[0]); //beginning point
start.marked = true; //it is marked
MyPoint last=null; //last point. this will be returned
queue.Add(points[0]);
while(queue.Count>0)
{
MyPoint current = queue.First(); //taking point from queue
queue.Remove(current); //removing it
foreach(MyPoint neighbour in current.Neighbours) //checking Neighbours
{
if (!neighbour.marked) //in neighbour isn't marked adding it to queue
{
neighbour.marked = true;
neighbour.parent = current;
queue.Add(neighbour);
}
//if neighbour is marked checking if it is startig point and if neighbour's parent is current point. if it is not that means that loop already got here so we start searching parents to got to starting point
else if(!neighbour.Equals(start) && !neighbour.parent.Equals(current))
{
current = neighbour;
while(true)
{
if (current.parent.Equals(start))
{
last = current;
break;
}
else
current = current.parent;
}
break;
}
}
}
return last;
}
But it doesn't work. The path it founds contains two points: start and it's first neighbour.
What am I doing wrong?
EDIT:
Forgot to mention... After horizontal connection there has to be vertical, horizontal, vertical and so on...
What is more in each row and column there need to be max two points (two or none) that are in the cycle. But this condition is the same as "The cycle has to be the shortest one".
First of all, you should change your representation to a more efficient one. You should make vertex a structure/class, which keeps the list of the connected vertices.
Having changed the representation, you can easily find the shortest cycle using breadth-first search.
You can speed the search up with the following trick: traverse the graph in the breadth-first order, marking the traversed vertices (and storing the "parent vertex" number on the way to the root at each vertex). AS soon as you find an already marked vertex, the search is finished. You can find the two paths from the found vertex to the root by walking back by the stored "parent" vertices.
Edit:
Are you sure you code is right? I tried the following:
while (queue.Count > 0)
{
MyPoint current = queue.First(); //taking point from queue
queue.Remove(current); //removing it
foreach (MyPoint neighbour in current.Neighbours) //checking Neighbours
{
if (!neighbour.marked) //if neighbour isn't marked adding it to queue
{
neighbour.marked = true;
neighbour.parent = current;
queue.Add(neighbour);
}
else if (!neighbour.Equals(current.parent)) // not considering own parent
{
// found!
List<MyPoint> loop = new List<MyPoint>();
MyPoint p = current;
do
{
loop.Add(p);
p = p.parent;
}
while (p != null);
p = neighbour;
while (!p.Equals(start))
{
loop.Add(p);
p = p.parent;
}
return loop;
}
}
}
return null;
instead of the corresponding part in your code (I changed the return type to List<MyPoint>, too). It works and correctly finds a smaller loop, consisting of 3 points: the red point, the point directly above and the point directly below.
That is what I have done. I don't know if it is optimised but it does work correctly. I have not done the sorting of the points as #marcog suggested.
private static bool LoopSearch2(bool[,] mask, int supIndexStart, int recIndexStart, out List<MyPoint> path)
{
List<MyPoint> points = new List<MyPoint>();
points.Add(new MyPoint { X = recIndexStart, Y = supIndexStart });
for (int i = 0; i < mask.GetLength(0); i++)
{
for (int j = 0; j < mask.GetLength(1); j++)
{
if (mask[i, j])
{
points.Add(new MyPoint { X = j, Y = i });
}
}
}
for (int i = 0; i < points.Count; i++)
{
for (int j = 0; j < points.Count; j++)
{
if (i != j)
{
if (points[i].X == points[j].X || points[i].Y == points[j].Y)
{
points[i].Neighbours.Add(points[j]);
}
}
}
}
List<MyPoint> queue = new List<MyPoint>();
MyPoint start = (points[0]);
start.marked = true;
queue.Add(points[0]);
path = new List<MyPoint>();
bool found = false;
while(queue.Count>0)
{
MyPoint current = queue.First();
queue.Remove(current);
foreach (MyPoint neighbour in current.Neighbours)
{
if (!neighbour.marked)
{
neighbour.marked = true;
neighbour.parent = current;
queue.Add(neighbour);
}
else
{
if (neighbour.parent != null && neighbour.parent.Equals(current))
continue;
if (current.parent == null)
continue;
bool previousConnectionHorizontal = current.parent.Y == current.Y;
bool currentConnectionHorizontal = current.Y == neighbour.Y;
if (previousConnectionHorizontal != currentConnectionHorizontal)
{
MyPoint prev = current;
while (true)
{
path.Add(prev);
if (prev.Equals(start))
break;
prev = prev.parent;
}
path.Reverse();
prev = neighbour;
while (true)
{
if (prev.Equals(start))
break;
path.Add(prev);
prev = prev.parent;
}
found = true;
break;
}
}
if (found) break;
}
if (found) break;
}
if (path.Count == 0)
{
path = null;
return false;
}
return true;
}
Your points removal step is worst case O(N^3) if implemented poorly, with the worst case being stripping a single point in each iteration. And since it doesn't always save you that much computation in the cycle detection, I'd avoid doing it as it also adds an extra layer of complexity to the solution.
Begin by creating an adjacency list from the set of points. You can do this efficiently in O(NlogN) if you sort the points by X and Y (separately) and iterate through the points in order of X and Y. Then to find the shortest cycle length (determined by number of points), start a BFS from each point by initially throwing all points on the queue. As you traverse an edge, store the source of the path along with the current point. Then you will know when the BFS returns to the source, in which case we've found a cycle. If you end up with an empty queue before finding a cycle, then none exists. Be careful not to track back immediately to the previous point or you will end up with a defunct cycle formed by two points. You might also want to avoid, for example, a cycle formed by the points (0, 0), (0, 2) and (0, 1) as this forms a straight line.
The BFS potentially has a worst case of being exponential, but I believe such a case can either be proven to not exist or be extremely rare as the denser the graph the quicker you'll find a cycle while the sparser the graph the smaller your queue will be. On average it is more likely to be closer to the same runtime as the adjacency list construction, or in the worst realistic cases O(N^2).
I think that I'd use an adapted variant of Dijkstra's algorithm which stops and returns the cycle whenever it arrives to any node for the second time. If this never happens, you don't have a cycle.
This approach should be much more efficient than a breadth-first or depth-first search, especially if you have many nodes. It is guarateed that you'll only visit each node once, thereby you have a linear runtime.

What is an Efficient algorithm to find Area of Overlapping Rectangles

My situation
Input: a set of rectangles
each rect is comprised of 4 doubles like this: (x0,y0,x1,y1)
they are not "rotated" at any angle, all they are "normal" rectangles that go "up/down" and "left/right" with respect to the screen
they are randomly placed - they may be touching at the edges, overlapping , or not have any contact
I will have several hundred rectangles
this is implemented in C#
I need to find
The area that is formed by their overlap - all the area in the canvas that more than one rectangle "covers" (for example with two rectangles, it would be the intersection)
I don't need the geometry of the overlap - just the area (example: 4 sq inches)
Overlaps shouldn't be counted multiple times - so for example imagine 3 rects that have the same size and position - they are right on top of each other - this area should be counted once (not three times)
Example
The image below contains thre rectangles: A,B,C
A and B overlap (as indicated by dashes)
B and C overlap (as indicated by dashes)
What I am looking for is the area where the dashes are shown
-
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA--------------BBB
AAAAAAAAAAAAAAAA--------------BBB
AAAAAAAAAAAAAAAA--------------BBB
AAAAAAAAAAAAAAAA--------------BBB
BBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBB
BBBBBB-----------CCCCCCCC
BBBBBB-----------CCCCCCCC
BBBBBB-----------CCCCCCCC
CCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCC
An efficient way of computing this area is to use a sweep algorithm. Let us assume that we sweep a vertical line L(x) through the union of rectangles U:
first of all, you need to build an event queue Q, which is, in this case, the ordered list of all x-coordinates (left and right) of the rectangles.
during the sweep, you should maintain a 1D datastructure, which should give you the total length of the intersection of L(x) and U. The important thing is that this length is constant between two consecutive events q and q' of Q. So, if l(q) denotes the total length of L(q+) (i.e. L just on the rightside of q) intersected with U, the area swept by L between events q and q' is exactly l(q)*(q' - q).
you just have to sum up all these swept areas to get the total one.
We still have to solve the 1D problem. You want a 1D structure, which computes dynamically a union of (vertical) segments. By dynamically, I mean that you sometimes add a new segment, and sometimes remove one.
I already detailed in my answer to this collapsing ranges question how to do it in a static way (which is in fact a 1D sweep). So if you want something simple, you can directly apply that (by recomputing the union for each event). If you want something more efficient, you just need to adapt it a bit:
assuming that you know the union of segments S1...Sn consists of disjoints segments D1...Dk. Adding Sn+1 is very easy, you just have to locate both ends of Sn+1 amongs the ends of D1...Dk.
assuming that you know the union of segments S1...Sn consists of disjoints segments D1...Dk, removing segment Si (assuming that Si was included in Dj) means recomputing the union of segments that Dj consisted of, except Si (using the static algorithm).
This is your dynamic algorithm. Assuming that you will use sorted sets with log-time location queries to represent D1...Dk, this is probably the most efficient non-specialized method you can get.
One way-out approach is to plot it to a canvas! Draw each rectangle using a semi-transparent colour. The .NET runtime will be doing the drawing in optimised, native code - or even using a hardware accelerator.
Then, you have to read-back the pixels. Is each pixel the background colour, the rectangle colour, or another colour? The only way it can be another colour is if two or more rectangles overlapped...
If this is too much of a cheat, I'd recommend the quad-tree as another answerer did, or the r-tree.
The simplest solution
import numpy as np
A = np.zeros((100, 100))
B = np.zeros((100, 100))
A[rect1.top : rect1.bottom, rect1.left : rect1.right] = 1
B[rect2.top : rect2.bottom, rect2.left : rect2.right] = 1
area_of_union = np.sum((A + B) > 0)
area_of_intersect = np.sum((A + B) > 1)
In this example, we create two zero-matrices that are the size of the canvas. For each rectangle, fill one of these matrices with ones where the rectangle takes up space. Then sum the matrices. Now sum(A+B > 0) is the area of the union, and sum(A+B > 1) is the area of the overlap. This example can easily generalize to multiple rectangles.
This is some quick and dirty code that I used in the TopCoder SRM 160 Div 2.
t = top
b = botttom
l = left
r = right
public class Rect
{
public int t, b, l, r;
public Rect(int _l, int _b, int _r, int _t)
{
t = _t;
b = _b;
l = _l;
r = _r;
}
public bool Intersects(Rect R)
{
return !(l > R.r || R.l > r || R.b > t || b > R.t);
}
public Rect Intersection(Rect R)
{
if(!this.Intersects(R))
return new Rect(0,0,0,0);
int [] horiz = {l, r, R.l, R.r};
Array.Sort(horiz);
int [] vert = {b, t, R.b, R.t};
Array.Sort(vert);
return new Rect(horiz[1], vert[1], horiz[2], vert[2]);
}
public int Area()
{
return (t - b)*(r-l);
}
public override string ToString()
{
return l + " " + b + " " + r + " " + t;
}
}
Here's something that off the top of my head sounds like it might work:
Create a dictionary with a double key, and a list of rectangle+boolean values, like this:
Dictionary< Double, List< KeyValuePair< Rectangle, Boolean>>> rectangles;
For each rectangle in your set, find the corresponding list for the x0 and the x1 values, and add the rectangle to that list, with a boolean value of true for x0, and false for x1. This way you now have a complete list of all the x-coordinates that each rectangle either enters (true) or leaves (false) the x-direction
Grab all the keys from that dictionary (all the distinct x-coordinates), sort them, and loop through them in order, make sure you can get at both the current x-value, and the next one as well (you need them both). This gives you individual strips of rectangles
Maintain a set of rectangles you're currently looking at, which starts out empty. For each x-value you iterate over in point 3, if the rectangle is registered with a true value, add it to the set, otherwise remove it.
For a strip, sort the rectangles by their y-coordinate
Loop through the rectangles in the strip, counting overlapping distances (unclear to me as of yet how to do this efficiently)
Calculate width of strip times height of overlapping distances to get areas
Example, 5 rectangles, draw on top of each other, from a to e:
aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbb
aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbb
aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbb
aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbb
aaaaaaaadddddddddddddddddddddddddddddbbbbbb
aaaaaaaadddddddddddddddddddddddddddddbbbbbb
ddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddd
ddddddddddddddeeeeeeeeeeeeeeeeee
ddddddddddddddeeeeeeeeeeeeeeeeee
ddddddddddddddeeeeeeeeeeeeeeeeee
ccccccccddddddddddddddeeeeeeeeeeeeeeeeee
ccccccccddddddddddddddeeeeeeeeeeeeeeeeee
cccccccccccc eeeeeeeeeeeeeeeeee
cccccccccccc eeeeeeeeeeeeeeeeee
cccccccccccc
cccccccccccc
Here's the list of x-coordinates:
v v v v v v v v v
|aaaaaaa|aa|aaaa | bbbbbbbbbb|bb|bbb
|aaaaaaa|aa|aaaa | bbbbbbbbbb|bb|bbb
|aaaaaaa|aa|aaaa | bbbbbbbbbb|bb|bbb
|aaaaaaa|aa|aaaa | bbbbbbbbbb|bb|bbb
|aaaaaaaddd|dddddddddd|ddddddddddddddbb|bbb
|aaaaaaaddd|dddddddddd|ddddddddddddddbb|bbb
| ddd|dddddddddd|dddddddddddddd |
| ddd|dddddddddd|dddddddddddddd |
| ddd|ddddddddddeeeeeeeeeeeeeeeeee
| ddd|ddddddddddeeeeeeeeeeeeeeeeee
| ddd|ddddddddddeeeeeeeeeeeeeeeeee
ccccccccddd|ddddddddddeeeeeeeeeeeeeeeeee
ccccccccddd|ddddddddddeeeeeeeeeeeeeeeeee
cccccccccccc eeeeeeeeeeeeeeeeee
cccccccccccc eeeeeeeeeeeeeeeeee
cccccccccccc
cccccccccccc
The list would be (where each v is simply given a coordinate starting at 0 and going up):
0: +a, +c
1: +d
2: -c
3: -a
4: +e
5: +b
6: -d
7: -e
8: -b
Each strip would thus be (rectangles sorted from top to bottom):
0-1: a, c
1-2: a, d, c
2-3: a, d
3-4: d
4-5: d, e
5-6: b, d, e
6-7: b, e
7-8: b
for each strip, the overlap would be:
0-1: none
1-2: a/d, d/c
2-3: a/d
3-4: none
4-5: d/e
5-6: b/d, d/e
6-7: none
7-8: none
I'd imagine that a variation of the sort + enter/leave algorithm for the top-bottom check would be doable as well:
sort the rectangles we're currently analyzing in the strip, top to bottom, for rectangles with the same top-coordinate, sort them by bottom coordinate as well
iterate through the y-coordinates, and when you enter a rectangle, add it to the set, when you leave a rectangle, remove it from the set
whenever the set has more than one rectangle, you have overlap (and if you make sure to add/remove all rectangles that have the same top/bottom coordinate you're currently looking at, multiple overlapping rectangles would not be a problem
For the 1-2 strip above, you would iterate like this:
0. empty set, zero sum
1. enter a, add a to set (1 rectangle in set)
2. enter d, add d to set (>1 rectangles in set = overlap, store this y-coordinate)
3. leave a, remove a from set (now back from >1 rectangles in set, add to sum: y - stored_y
4. enter c, add c to set (>1 rectangles in set = overlap, store this y-coordinate)
5. leave d, remove d from set (now back from >1 rectangles in set, add to sum: y - stored_y)
6. multiply sum with width of strip to get overlapping areas
You would not actually have to maintain an actual set here either, just the count of the rectangles you're inside, whenever this goes from 1 to 2, store the y, and whenever it goes from 2 down to 1, calculate current y - stored y, and sum this difference.
Hope this was understandable, and as I said, this is off the top of my head, not tested in any way.
Using the example:
1 2 3 4 5 6
1 +---+---+
| |
2 + A +---+---+
| | B |
3 + + +---+---+
| | | | |
4 +---+---+---+---+ +
| |
5 + C +
| |
6 +---+---+
1) collect all the x coordinates (both left and right) into a list, then sort it and remove duplicates
1 3 4 5 6
2) collect all the y coordinates (both top and bottom) into a list, then sort it and remove duplicates
1 2 3 4 6
3) create a 2D array by number of gaps between the unique x coordinates * number of gaps between the unique y coordinates.
4 * 4
4) paint all the rectangles into this grid, incrementing the count of each cell it occurs over:
1 3 4 5 6
1 +---+
| 1 | 0 0 0
2 +---+---+---+
| 1 | 1 | 1 | 0
3 +---+---+---+---+
| 1 | 1 | 2 | 1 |
4 +---+---+---+---+
0 0 | 1 | 1 |
6 +---+---+
5) the sum total of the areas of the cells in the grid that have a count greater than one is the area of overlap. For better efficiency in sparse use-cases, you can actually keep a running total of the area as you paint the rectangles, each time you move a cell from 1 to 2.
In the question, the rectangles are described as being four doubles. Doubles typically contain rounding errors, and error might creep into your computed area of overlap. If the legal coordinates are at finite points, consider using an integer representation.
PS using the hardware accelerator as in my other answer is not such a shabby idea, if the resolution is acceptable. Its also easy to implement in a lot less code than the approach I outline above. Horses for courses.
Here's the code I wrote for the area sweep algorithm:
#include <iostream>
#include <vector>
using namespace std;
class Rectangle {
public:
int x[2], y[2];
Rectangle(int x1, int y1, int x2, int y2) {
x[0] = x1;
y[0] = y1;
x[1] = x2;
y[1] = y2;
};
void print(void) {
cout << "Rect: " << x[0] << " " << y[0] << " " << x[1] << " " << y[1] << " " <<endl;
};
};
// return the iterator of rec in list
vector<Rectangle *>::iterator bin_search(vector<Rectangle *> &list, int begin, int end, Rectangle *rec) {
cout << begin << " " <<end <<endl;
int mid = (begin+end)/2;
if (list[mid]->y[0] == rec->y[0]) {
if (list[mid]->y[1] == rec->y[1])
return list.begin() + mid;
else if (list[mid]->y[1] < rec->y[1]) {
if (mid == end)
return list.begin() + mid+1;
return bin_search(list,mid+1,mid,rec);
}
else {
if (mid == begin)
return list.begin()+mid;
return bin_search(list,begin,mid-1,rec);
}
}
else if (list[mid]->y[0] < rec->y[0]) {
if (mid == end) {
return list.begin() + mid+1;
}
return bin_search(list, mid+1, end, rec);
}
else {
if (mid == begin) {
return list.begin() + mid;
}
return bin_search(list, begin, mid-1, rec);
}
}
// add rect to rects
void add_rec(Rectangle *rect, vector<Rectangle *> &rects) {
if (rects.size() == 0) {
rects.push_back(rect);
}
else {
vector<Rectangle *>::iterator it = bin_search(rects, 0, rects.size()-1, rect);
rects.insert(it, rect);
}
}
// remove rec from rets
void remove_rec(Rectangle *rect, vector<Rectangle *> &rects) {
vector<Rectangle *>::iterator it = bin_search(rects, 0, rects.size()-1, rect);
rects.erase(it);
}
// calculate the total vertical length covered by rectangles in the active set
int vert_dist(vector<Rectangle *> as) {
int n = as.size();
int totallength = 0;
int start, end;
int i = 0;
while (i < n) {
start = as[i]->y[0];
end = as[i]->y[1];
while (i < n && as[i]->y[0] <= end) {
if (as[i]->y[1] > end) {
end = as[i]->y[1];
}
i++;
}
totallength += end-start;
}
return totallength;
}
bool mycomp1(Rectangle* a, Rectangle* b) {
return (a->x[0] < b->x[0]);
}
bool mycomp2(Rectangle* a, Rectangle* b) {
return (a->x[1] < b->x[1]);
}
int findarea(vector<Rectangle *> rects) {
vector<Rectangle *> start = rects;
vector<Rectangle *> end = rects;
sort(start.begin(), start.end(), mycomp1);
sort(end.begin(), end.end(), mycomp2);
// active set
vector<Rectangle *> as;
int n = rects.size();
int totalarea = 0;
int current = start[0]->x[0];
int next;
int i = 0, j = 0;
// big loop
while (j < n) {
cout << "loop---------------"<<endl;
// add all recs that start at current
while (i < n && start[i]->x[0] == current) {
cout << "add" <<endl;
// add start[i] to AS
add_rec(start[i], as);
cout << "after" <<endl;
i++;
}
// remove all recs that end at current
while (j < n && end[j]->x[1] == current) {
cout << "remove" <<endl;
// remove end[j] from AS
remove_rec(end[j], as);
cout << "after" <<endl;
j++;
}
// find next event x
if (i < n && j < n) {
if (start[i]->x[0] <= end[j]->x[1]) {
next = start[i]->x[0];
}
else {
next = end[j]->x[1];
}
}
else if (j < n) {
next = end[j]->x[1];
}
// distance to next event
int horiz = next - current;
cout << "horiz: " << horiz <<endl;
// figure out vertical dist
int vert = vert_dist(as);
cout << "vert: " << vert <<endl;
totalarea += vert * horiz;
current = next;
}
return totalarea;
}
int main() {
vector<Rectangle *> rects;
rects.push_back(new Rectangle(0,0,1,1));
rects.push_back(new Rectangle(1,0,2,3));
rects.push_back(new Rectangle(0,0,3,3));
rects.push_back(new Rectangle(1,0,5,1));
cout << findarea(rects) <<endl;
}
You can simplify this problem quite a bit if you split each rectangle into smaller rectangles. Collect all of the X and Y coordinates of all the rectangles, and these become your split points - if a rectangle crosses the line, split it in two. When you're done, you have a list of rectangles that overlap either 0% or 100%, if you sort them it should be easy to find the identical ones.
There is a solution listed at the link http://codercareer.blogspot.com/2011/12/no-27-area-of-rectangles.html for finding the total area of multiple rectangles such that the overlapped area is counted only once.
The above solution can be extended to compute only the overlapped area(and that too only once even if the overlapped area is covered by multiple rectangles) with horizontal sweep lines for every pair of consecutive vertical sweep lines.
If aim is just to find out the total area covered by the all the rectangles, then horizontal sweep lines are not needed and just a merge of all the rectangles between two vertical sweep lines would give the area.
On the other hand, if you want to compute the overlapped area only, the horizontal sweep lines are needed to find out how many rectangles are overlapping in between vertical (y1, y2) sweep lines.
Here is the working code for the solution I implemented in Java.
import java.io.*;
import java.util.*;
class Solution {
static class Rectangle{
int x;
int y;
int dx;
int dy;
Rectangle(int x, int y, int dx, int dy){
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
}
Range getBottomLeft(){
return new Range(x, y);
}
Range getTopRight(){
return new Range(x + dx, y + dy);
}
#Override
public int hashCode(){
return (x+y+dx+dy)/4;
}
#Override
public boolean equals(Object other){
Rectangle o = (Rectangle) other;
return o.x == this.x && o.y == this.y && o.dx == this.dx && o.dy == this.dy;
}
#Override
public String toString(){
return String.format("X = %d, Y = %d, dx : %d, dy : %d", x, y, dx, dy);
}
}
static class RW{
Rectangle r;
boolean start;
RW (Rectangle r, boolean start){
this.r = r;
this.start = start;
}
#Override
public int hashCode(){
return r.hashCode() + (start ? 1 : 0);
}
#Override
public boolean equals(Object other){
RW o = (RW)other;
return o.start == this.start && o.r.equals(this.r);
}
#Override
public String toString(){
return "Rectangle : " + r.toString() + ", start = " + this.start;
}
}
static class Range{
int l;
int u;
public Range(int l, int u){
this.l = l;
this.u = u;
}
#Override
public int hashCode(){
return (l+u)/2;
}
#Override
public boolean equals(Object other){
Range o = (Range) other;
return o.l == this.l && o.u == this.u;
}
#Override
public String toString(){
return String.format("L = %d, U = %d", l, u);
}
}
static class XComp implements Comparator<RW>{
#Override
public int compare(RW rw1, RW rw2){
//TODO : revisit these values.
Integer x1 = -1;
Integer x2 = -1;
if(rw1.start){
x1 = rw1.r.x;
}else{
x1 = rw1.r.x + rw1.r.dx;
}
if(rw2.start){
x2 = rw2.r.x;
}else{
x2 = rw2.r.x + rw2.r.dx;
}
return x1.compareTo(x2);
}
}
static class YComp implements Comparator<RW>{
#Override
public int compare(RW rw1, RW rw2){
//TODO : revisit these values.
Integer y1 = -1;
Integer y2 = -1;
if(rw1.start){
y1 = rw1.r.y;
}else{
y1 = rw1.r.y + rw1.r.dy;
}
if(rw2.start){
y2 = rw2.r.y;
}else{
y2 = rw2.r.y + rw2.r.dy;
}
return y1.compareTo(y2);
}
}
public static void main(String []args){
Rectangle [] rects = new Rectangle[4];
rects[0] = new Rectangle(10, 10, 10, 10);
rects[1] = new Rectangle(15, 10, 10, 10);
rects[2] = new Rectangle(20, 10, 10, 10);
rects[3] = new Rectangle(25, 10, 10, 10);
int totalArea = getArea(rects, false);
System.out.println("Total Area : " + totalArea);
int overlapArea = getArea(rects, true);
System.out.println("Overlap Area : " + overlapArea);
}
static int getArea(Rectangle []rects, boolean overlapOrTotal){
printArr(rects);
// step 1: create two wrappers for every rectangle
RW []rws = getWrappers(rects);
printArr(rws);
// steps 2 : sort rectangles by their x-coordinates
Arrays.sort(rws, new XComp());
printArr(rws);
// step 3 : group the rectangles in every range.
Map<Range, List<Rectangle>> rangeGroups = groupRects(rws, true);
for(Range xrange : rangeGroups.keySet()){
List<Rectangle> xRangeRects = rangeGroups.get(xrange);
System.out.println("Range : " + xrange);
System.out.println("Rectangles : ");
for(Rectangle rectx : xRangeRects){
System.out.println("\t" + rectx);
}
}
// step 4 : iterate through each of the pairs and their rectangles
int sum = 0;
for(Range range : rangeGroups.keySet()){
List<Rectangle> rangeRects = rangeGroups.get(range);
sum += getOverlapOrTotalArea(rangeRects, range, overlapOrTotal);
}
return sum;
}
static Map<Range, List<Rectangle>> groupRects(RW []rws, boolean isX){
//group the rws with either x or y coordinates.
Map<Range, List<Rectangle>> rangeGroups = new HashMap<Range, List<Rectangle>>();
List<Rectangle> rangeRects = new ArrayList<Rectangle>();
int i=0;
int prev = Integer.MAX_VALUE;
while(i < rws.length){
int curr = isX ? (rws[i].start ? rws[i].r.x : rws[i].r.x + rws[i].r.dx): (rws[i].start ? rws[i].r.y : rws[i].r.y + rws[i].r.dy);
if(prev < curr){
Range nRange = new Range(prev, curr);
rangeGroups.put(nRange, rangeRects);
rangeRects = new ArrayList<Rectangle>(rangeRects);
}
prev = curr;
if(rws[i].start){
rangeRects.add(rws[i].r);
}else{
rangeRects.remove(rws[i].r);
}
i++;
}
return rangeGroups;
}
static int getOverlapOrTotalArea(List<Rectangle> rangeRects, Range range, boolean isOverlap){
//create horizontal sweep lines similar to vertical ones created above
// Step 1 : create wrappers again
RW []rws = getWrappers(rangeRects);
// steps 2 : sort rectangles by their y-coordinates
Arrays.sort(rws, new YComp());
// step 3 : group the rectangles in every range.
Map<Range, List<Rectangle>> yRangeGroups = groupRects(rws, false);
//step 4 : for every range if there are more than one rectangles then computer their area only once.
int sum = 0;
for(Range yRange : yRangeGroups.keySet()){
List<Rectangle> yRangeRects = yRangeGroups.get(yRange);
if(isOverlap){
if(yRangeRects.size() > 1){
sum += getArea(range, yRange);
}
}else{
if(yRangeRects.size() > 0){
sum += getArea(range, yRange);
}
}
}
return sum;
}
static int getArea(Range r1, Range r2){
return (r2.u-r2.l)*(r1.u-r1.l);
}
static RW[] getWrappers(Rectangle []rects){
RW[] wrappers = new RW[rects.length * 2];
for(int i=0,j=0;i<rects.length;i++, j+=2){
wrappers[j] = new RW(rects[i], true);
wrappers[j+1] = new RW(rects[i], false);
}
return wrappers;
}
static RW[] getWrappers(List<Rectangle> rects){
RW[] wrappers = new RW[rects.size() * 2];
for(int i=0,j=0;i<rects.size();i++, j+=2){
wrappers[j] = new RW(rects.get(i), true);
wrappers[j+1] = new RW(rects.get(i), false);
}
return wrappers;
}
static void printArr(Object []a){
for(int i=0; i < a.length;i++){
System.out.println(a[i]);
}
System.out.println();
}
The following answer should give the total Area only once.
it comes previous answers, but implemented now in C#.
It works also with floats (or double, if you need[it doesn't itterate over the VALUES).
Credits:
http://codercareer.blogspot.co.il/2011/12/no-27-area-of-rectangles.html
EDIT:
The OP asked for the overlapping area - thats obviously very simple:
var totArea = rects.Sum(x => x.Width * x.Height);
and then the answer is:
var overlappingArea =totArea-GetArea(rects)
Here is the code:
#region rectangle overlapping
/// <summary>
/// see algorithm for detecting overlapping areas here: https://stackoverflow.com/a/245245/3225391
/// or easier here:
/// http://codercareer.blogspot.co.il/2011/12/no-27-area-of-rectangles.html
/// </summary>
/// <param name="dim"></param>
/// <returns></returns>
public static float GetArea(RectangleF[] rects)
{
List<float> xs = new List<float>();
foreach (var item in rects)
{
xs.Add(item.X);
xs.Add(item.Right);
}
xs = xs.OrderBy(x => x).Cast<float>().ToList();
rects = rects.OrderBy(rec => rec.X).Cast<RectangleF>().ToArray();
float area = 0f;
for (int i = 0; i < xs.Count - 1; i++)
{
if (xs[i] == xs[i + 1])//not duplicate
continue;
int j = 0;
while (rects[j].Right < xs[i])
j++;
List<Range> rangesOfY = new List<Range>();
var rangeX = new Range(xs[i], xs[i + 1]);
GetRangesOfY(rects, j, rangeX, out rangesOfY);
area += GetRectArea(rangeX, rangesOfY);
}
return area;
}
private static void GetRangesOfY(RectangleF[] rects, int rectIdx, Range rangeX, out List<Range> rangesOfY)
{
rangesOfY = new List<Range>();
for (int j = rectIdx; j < rects.Length; j++)
{
if (rangeX.less < rects[j].Right && rangeX.greater > rects[j].Left)
{
rangesOfY = Range.AddRange(rangesOfY, new Range(rects[j].Top, rects[j].Bottom));
#if DEBUG
Range rectXRange = new Range(rects[j].Left, rects[j].Right);
#endif
}
}
}
static float GetRectArea(Range rangeX, List<Range> rangesOfY)
{
float width = rangeX.greater - rangeX.less,
area = 0;
foreach (var item in rangesOfY)
{
float height = item.greater - item.less;
area += width * height;
}
return area;
}
internal class Range
{
internal static List<Range> AddRange(List<Range> lst, Range rng2add)
{
if (lst.isNullOrEmpty())
{
return new List<Range>() { rng2add };
}
for (int i = lst.Count - 1; i >= 0; i--)
{
var item = lst[i];
if (item.IsOverlapping(rng2add))
{
rng2add.Merge(item);
lst.Remove(item);
}
}
lst.Add(rng2add);
return lst;
}
internal float greater, less;
public override string ToString()
{
return $"ln{less} gtn{greater}";
}
internal Range(float less, float greater)
{
this.less = less;
this.greater = greater;
}
private void Merge(Range rng2add)
{
this.less = Math.Min(rng2add.less, this.less);
this.greater = Math.Max(rng2add.greater, this.greater);
}
private bool IsOverlapping(Range rng2add)
{
return !(less > rng2add.greater || rng2add.less > greater);
//return
// this.greater < rng2add.greater && this.greater > rng2add.less
// || this.less > rng2add.less && this.less < rng2add.greater
// || rng2add.greater < this.greater && rng2add.greater > this.less
// || rng2add.less > this.less && rng2add.less < this.greater;
}
}
#endregion rectangle overlapping
If your rectangles are going to be sparse (mostly not intersecting) then it might be worth a look at recursive dimensional clustering. Otherwise a quad-tree seems to be the way to go (as has been mentioned by other posters.
This is a common problem in collision detection in computer games, so there is no shortage of resources suggesting ways to solve it.
Here is a nice blog post summarizing RCD.
Here is a Dr.Dobbs article summarizing various collision detection algorithms, which would be suitable.
This type of collision detection is often called AABB (Axis Aligned Bounding Boxes), that's a good starting point for a google search.
You can find the overlap on the x and on the y axis and multiply those.
int LineOverlap(int line1a, line1b, line2a, line2b)
{
// assume line1a <= line1b and line2a <= line2b
if (line1a < line2a)
{
if (line1b > line2b)
return line2b-line2a;
else if (line1b > line2a)
return line1b-line2a;
else
return 0;
}
else if (line2a < line1b)
return line2b-line1a;
else
return 0;
}
int RectangleOverlap(Rect rectA, rectB)
{
return LineOverlap(rectA.x1, rectA.x2, rectB.x1, rectB.x2) *
LineOverlap(rectA.y1, rectA.y2, rectB.y1, rectB.y2);
}
I found a different solution than the sweep algorithm.
Since your rectangles are all rectangular placed, the horizontal and vertical lines of the rectangles will form a rectangular irregular grid. You can 'paint' the rectangles on this grid; which means, you can determine which fields of the grid will be filled out. Since the grid lines are formed from the boundaries of the given rectangles, a field in this grid will always either completely empty or completely filled by an rectangle.
I had to solve the problem in Java, so here's my solution: http://pastebin.com/03mss8yf
This function calculates of the complete area occupied by the rectangles. If you are interested only in the 'overlapping' part, you must extend the code block between lines 70 and 72. Maybe you can use a second set to store which grid fields are used more than once. Your code between line 70 and 72 should be replaced with a block like:
GridLocation gl = new GridLocation(curX, curY);
if(usedLocations.contains(gl) && usedLocations2.add(gl)) {
ret += width*height;
} else {
usedLocations.add(gl);
}
The variable usedLocations2 here is of the same type as usedLocations; it will be constructed
at the same point.
I'm not really familiar with complexity calculations; so I don't know which of the two solutions (sweep or my grid solution) will perform/scale better.
Considering we have two rectangles (A and B) and we have their bottom left (x1,y1) and top right (x2,y2) coordination. The Using following piece of code you can calculate the overlapped area in C++.
#include <iostream>
using namespace std;
int rectoverlap (int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2)
{
int width, heigh, area;
if (ax2<bx1 || ay2<by1 || ax1>bx2 || ay1>by2) {
cout << "Rectangles are not overlapped" << endl;
return 0;
}
if (ax2>=bx2 && bx1>=ax1){
width=bx2-bx1;
heigh=by2-by1;
} else if (bx2>=ax2 && ax1>=bx1) {
width=ax2-ax1;
heigh=ay2-ay1;
} else {
if (ax2>bx2){
width=bx2-ax1;
} else {
width=ax2-bx1;
}
if (ay2>by2){
heigh=by2-ay1;
} else {
heigh=ay2-by1;
}
}
area= heigh*width;
return (area);
}
int main()
{
int ax1,ay1,ax2,ay2,bx1,by1,bx2,by2;
cout << "Inter the x value for bottom left for rectangle A" << endl;
cin >> ax1;
cout << "Inter the y value for bottom left for rectangle A" << endl;
cin >> ay1;
cout << "Inter the x value for top right for rectangle A" << endl;
cin >> ax2;
cout << "Inter the y value for top right for rectangle A" << endl;
cin >> ay2;
cout << "Inter the x value for bottom left for rectangle B" << endl;
cin >> bx1;
cout << "Inter the y value for bottom left for rectangle B" << endl;
cin >> by1;
cout << "Inter the x value for top right for rectangle B" << endl;
cin >> bx2;
cout << "Inter the y value for top right for rectangle B" << endl;
cin >> by2;
cout << "The overlapped area is " << rectoverlap (ax1, ay1, ax2, ay2, bx1, by1, bx2, by2) << endl;
}
The post by user3048546 contains an error in the logic on lines 12-17. Here is a working implementation:
int rectoverlap (int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2)
{
int width, height, area;
if (ax2<bx1 || ay2<by1 || ax1>bx2 || ay1>by2) {
cout << "Rectangles are not overlapped" << endl;
return 0;
}
if (ax2>=bx2 && bx1>=ax1){
width=bx2-bx1;
} else if (bx2>=ax2 && ax1>=bx1) {
width=ax2-ax1;
} else if (ax2>bx2) {
width=bx2-ax1;
} else {
width=ax2-bx1;
}
if (ay2>=by2 && by1>=ay1){
height=by2-by1;
} else if (by2>=ay2 && ay1>=by1) {
height=ay2-ay1;
} else if (ay2>by2) {
height=by2-ay1;
} else {
height=ay2-by1;
}
area = heigh*width;
return (area);
}

Resources