depth first search recursion in matrix - depth-first-search

http://codeforces.com/contest/540/problem/C
This problem is solved using depth first recursion on matrix and i got this code for the problem. Can anyone explain why/where recursion is working on this matrix?
#include <bits/stdc++.h>
using namespace std;
int a, b, used[600][600];
char c;
void dfs( int x, int y )
{
used[x][y]++;
if( used[x][y] >= 3 || x < 1 || y < 1 || x > a || y > b )
return;
dfs(x + 1, y);
dfs(x - 1, y);
dfs(x, y + 1);
dfs(x, y - 1);
}
int main()
{
int i, j;
cin >> a >> b;
for( i = 1; i <= a; i++ ){
for( j = 1; j <= b; j++ ){
cin >> c;
if( c == '.' ) used[i][j] = 1;
else used[i][j] = 2;
}
}
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
used[x1][y1] = 1;
dfs(x1, y1);
if( used[x2][y2] >= 3 ) cout << "YES";
else cout << "NO";
}

This problem can be thought of as a graph with edges connecting cells(nodes) which are adjacent i.e. share a boundary.
When DFS is implemented using a stack structure it is easier to see recursion. Here recursion is implemented in the form of function calls. We would call dfs for only those nodes which are:
directly reachable from the current node we are examining(which are all the cells
adjacent to (x, y)).
Call to
dfs(x, y);
results in calling
dfs(x + i, y + j);
for (i, j) = {(-1, 0), (0, 1), (1, 0), (0, -1)}. As a consequence, the progam status word(variables, instruction pointer etc.) at the time
dfs(x + 1, y) is called, is pushed implicitly onto the stack memory used by the program. These calls result in increasing the count of cells adjacent to (x, y) by 1.
Recursion unfolds when
if( used[x][y] >= 3 || x < 1 || y < 1 || x > a || y > b )
condition is met resulting in return to coordinates(node) which called dfs on (x, y) OR when all the calls to
dfs(x + i, y + j) for (i, j) = {(-1, 0), (0, 1), (1, 0), (0, -1)} have returned control to dfs(x, y) i.e. the after the line dfs(x, y - 1).
So recursion is all around when you are calling dfs(x -1, y), dfs(x, y -1) etc. within dfs(x, y);

Related

What is the difference between BFS and DFS algorithms?

A timeout occurred when solving an algorithm problem with BFS. However, there is a problem that can be solved with DFS. Why does this difference occur?
The problem is to calculate the number of arrivals from (1,1) to (N, N) by moving horizontally, vertically, or diagonally.
It took 1331.0ms if the problem was solved by BFS (worst case), and 62.0ms when it was solved by DFS. (I have created and tested 16 * 16 arrays.)
Attach the issue URL. (But please understand that it is Korean.)
URL> https://www.acmicpc.net/problem/17070
The answer I want to hear is...
I thought the BFS algorithm would be faster, but why is DFS faster?
Is BFS slower because there are many elements in the queue? I want to know the exact reason.
Implementation code>
class Location {
int x;
int y;
int dir;
public Location(int x, int y, int dir) {
super();
this.x = x;
this.y = y;
this.dir = dir;
}
}
public class Main {
static int[][] map;
static int Answer;
static int N;
public static void main(String args[]) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
N = Integer.parseInt(br.readLine());
map = new int[N + 1][N + 1];
for (int i = 1; i <= N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 1; j <= N; j++)
map[i][j] = Integer.parseInt(st.nextToken());
}
DFS(1, 2, 0);
System.out.println(Answer);
Answer = 0;
BFS(1, 2, 0);
System.out.println(Answer);
br.close();
}
static void DFS(int x, int y, int pre) {
if (x == N && y == N) {
Answer++;
return;
}
if (pre == 0) {
if (y + 1 <= N && map[x][y + 1] == 0)
DFS(x, y + 1, 0);
if (y + 1 <= N && map[x][y + 1] == 0 && x + 1 <= N && map[x + 1][y] == 0 && map[x + 1][y + 1] == 0)
DFS(x + 1, y + 1, 1);
} else if (pre == 1) {
if (y + 1 <= N && map[x][y + 1] == 0)
DFS(x, y + 1, 0);
if (x + 1 <= N && map[x + 1][y] == 0)
DFS(x + 1, y, 2);
if (y + 1 <= N && map[x][y + 1] == 0 && x + 1 <= N && map[x + 1][y] == 0 && map[x + 1][y + 1] == 0)
DFS(x + 1, y + 1, 1);
} else {
if (x + 1 <= N && map[x + 1][y] == 0)
DFS(x + 1, y, 2);
if (y + 1 <= N && map[x][y + 1] == 0 && x + 1 <= N && map[x + 1][y] == 0 && map[x + 1][y + 1] == 0)
DFS(x + 1, y + 1, 1);
}
}
static void BFS(int startX, int startY, int dir) {
ArrayDeque<Location> arrayDeque = new ArrayDeque<>();
arrayDeque.add(new Location(startX, startY, dir));
Location location;
int x, y, pre;
while(!arrayDeque.isEmpty()) {
location = arrayDeque.remove();
x = location.x;
y = location.y;
pre = location.dir;
if(x == N-1 && y == N-1) {
Answer++; continue;
}
if (pre == 0) {
if (y + 1 <= N && map[x][y + 1] == 0)
arrayDeque.add(new Location(x, y + 1, 0));
if (y + 1 <= N && map[x][y + 1] == 0 && x + 1 <= N && map[x + 1][y] == 0 && map[x + 1][y + 1] == 0)
arrayDeque.add(new Location(x + 1, y + 1, 1));
} else if (pre == 1) {
if (y + 1 <= N && map[x][y + 1] == 0)
arrayDeque.add(new Location(x, y + 1, 0));
if (x + 1 <= N && map[x + 1][y] == 0)
arrayDeque.add(new Location(x + 1, y, 2));
if (y + 1 <= N && map[x][y + 1] == 0 && x + 1 <= N && map[x + 1][y] == 0 && map[x + 1][y + 1] == 0)
arrayDeque.add(new Location(x + 1, y + 1, 1));
} else {
if (x + 1 <= N && map[x + 1][y] == 0)
arrayDeque.add(new Location(x + 1, y, 2));
if (y + 1 <= N && map[x][y + 1] == 0 && x + 1 <= N && map[x + 1][y] == 0 && map[x + 1][y + 1] == 0)
arrayDeque.add(new Location(x + 1, y + 1, 1));
}
}
}
}
Both BFS and DFS have O(|V| + |E|) time complexity, and the time difference you are experiencing is most probably rooted in a mistake in the implementation of the BFS which is breaking the loop invariant.
One of the more common mistakes made while implementing BFS is adding the same element to the queue multiple times. One should only add a vertex v to the queue once, so that you can ensure it's removed a single time. Unless you do so, then the asymptotic runtime (i.e. its complexity) will not be linear anymore. You can see the relevant CLRS chapter for the proof of that, based on the loop invariant concept they introduce.
In other words, BFS is a traversal algorithm. It finds out which vertices are reachable, not the number of routes to reach every vertex v. If you try to compute the number of ways Kv to reach to each v from (1, 1) through BFS, the complexity becomes larger than linear. If the problem asks you to find Kv, then your approach should be to use memoization and dynamic programming, not BFS.
Specifically, based on the code you provided, your algorithm does not seem to keep track of whether a vertex (i e. a cell in the grid) was previously explored or not. This causes the vertices to be explored multiple times, which beats the point of using a graph traversal algorithm like BFS and DFS. Using the terminology I mentioned above, you are going against the loop invariant of BFS, which states that each vertex is popped from the queue only once. This causes the complexity of your code to go much higher than linear.
You should look into the term memoization and figure out a way to find a solutions for (N, N), using the solutions you compute only once for (N-1, N-1), (N-1, N) and (N, N-1).
Your BFS implementation uses dynamic memory allocation and an ArrayDeque; your DFS avoids that. That will increase the cost per node for your BFS, although it is odd that it would be that much.
You could try to allocate a new Location in each call of DFS (and possibly add and remove it from an ArrayDeque) and see if that causes the same performance loss.
Additionally your BFS doesn't stop directly when x=y=N; but I don't see that it significantly increases the run-time.

Print all combination of a set after pairing consecutive numbers

Question is such that given a set of numbers we have to write a recursive program which prints all possible combination after pairing consecutive numbers or leaving them single.
<div>
Ex set 1,2,3,4,5,6
Output
<ul>
<li>1,2,3,4,5,6</li>
<li>12,3,4,5,6</li>
<li>1,23,4,5,6</li>
<li>1,2,34,5,6</li>
<li>1,2,3,45,6</li>
<li>1,2,3,4,56</li>
<li>12,34,5,6</li>
<li>12,3,45,6</li>
<li>12,3,4,56</li>
<li>1,23,45,6</li>
<li>1,23,4,56</li>
<li>1,2,34,56</li>
<li>12,34,56</li>
</div>
I use c++ to code.
Suppose the given set is a(a[0], a[1], ..., a[n - 1]), and the length of a is n
And the current answer is saved in b
void dfs(int pos, int depth)
{
if(pos >= n)
for(int i = 0; i < depth; ++i)
printf("%d%c", b[i], i == depth - 1 ? '\n' : ',');
else
{
b[depth] = a[pos];
dfs(pos + 1, depth + 1);
if(pos + 1 < n)
{
int c = 1, x = a[pos];
while(x) c *= 10, x /= 10;
b[depth] = a[pos] * c + a[pos + 1];
dfs(pos + 2, depth + 1);
}
}
}

Using extended euclidean algorithm to find number of intersections of a line segment with points on a 2D grid

In the grid constructed by grid points (M*x, M*y) and given the point A(x1,y1) and point B(x2,y2) where all the variables are integers. I need to check how many grid points lie on the line segment from point A to point B. I know that it can be done by using the extended euclidean algorithm somehow, but I have no clue on how to do it. I would appreciate your help.
Rephrased, you want to determine how many numbers t satisfy
(1) M divides (1-t) x1 + t x2
(2) M divides (1-t) y1 + t y2
(3) 0 <= t <= 1.
Let's focus on (1). We introduce an integer variable q to represent the divisibility constraint and solve for t:
exists integer q, M q = (1-t) x1 + t x2
exists integer q, M q - x1 = (x2 - x1) t.
If x1 is not equal to x2, then this gives a periodic set of possibilities of the form t in {a + b q | q integer}, where a and b are fractions. Otherwise, all t or no t are solutions.
The extended Euclidean algorithm is useful for intersecting the solution sets arising from (1) and (2). Suppose that we want to compute the intersection
{a + b q | q integer} intersect {c + d s | s integer}.
By expressing a generic common element in two different ways, we arrive at a linear Diophantine equation:
a + b q = c + d s,
where a, b, c, d are constant and q, s are integer. Let's clear denominators and gather terms into one equation
A q + B s = C,
where A, B, C are integers. This equation has solutions if and only if the greatest common divisor g of A and B also divides C. Use the extended Euclidean algorithm to compute integer coefficients u, v such that
A u + B v = g.
Then we have a solution
q = u (C/g) + k (B/g)
s = v (C/g) - k (A/g)
for each integer k.
Finally, we have to take constraint (3) into consideration. This should boil down to some arithmetic and one floor division, but I'd rather not work out the details (the special cases of what I've written so far already will take quite a lot of your time).
Let's dX = Abs(x2-x1) and dY = Abs(y2 - y1)
Then number of lattice points on the segment is
P = GCD(dX, dY) + 1
(including start and end points)
where GCD is the greatest common divisor (through usual (not extended) Euclidean algorithm)
(See last Properties here)
Following instructions of Mr. David Eisenstat I have managed to write a program in c++ that calculates the answer.
#include <iostream>
#include <math.h>
using namespace std;
int gcd (int A, int B, int &u, int &v)
{
int Ad = 1;
int Bd = 1;
if (A < 0) { Ad = -1; A = -A; }
if (B < 0) { Bd = -1; B = -B; }
int x = 1, y = 0;
u = 0, v = 1;
while (A != 0)
{
int q = B/A;
int r = B%A;
int m = u-x*q;
int n = v-y*q;
B = A;
A = r;
u = x;
v = y;
x = m;
y = n;
}
u *= Ad;
v *= Bd;
return B;
}
int main(int argc, const char * argv[])
{
int t;
scanf("%d", &t);
for (int i = 0; i<t; i++) {
int x1, x2, y1, y2, M;
scanf("%d %d %d %d %d", &M, &x1, &y1, &x2, &y2);
if ( x1 == x2 ) // vertical line
{
if (x1%M != 0) { // in between the horizontal lines
cout << 0 << endl;
} else
{
int r = abs((y2-y1)/M); // number of points
if (y2%M == 0 || y1%M == 0) // +1 if the line starts or ends on the point
r++;
cout << r << endl;
}
} else {
if (x2 < x1)
{
int c;
c = x1;
x1 = x2;
x2 = c;
}
int A, B, C;
C = x1*y2-y1*x2;
A = M*(y2-y1);
B = -M*(x2-x1);
int u, v;
int g = gcd(A, B, u, v);
//cout << "A: " << A << " B: " << B << " C: " << C << endl;
//cout << A << "*" << u <<"+"<< B <<"*"<<v<<"="<<g<<endl;
double a = -x1/(double)(x2-x1);
double b = M/(double)(x2-x1);
double Z = (-a-C*b/g*u)*g/(B*b);
double Y = (1-a-C*b/g*u)*g/(B*b);
cout << floor(Z) - ceil(Y) + 1 << endl;
}
}
return 0;
}
Thank you for your help! Please check if all special cases are taken into consideration.

How to convert DFS algorithm using recursion to algorithm with normal iteration?

I have implemented successfully DFS (Deep First Search) Algorithm by using recursion but I dont know how to use normal iteration instead.
Below is my code with recursive calls.
data[1000][1000];
mark[1000][1000];// The array marks vertex visited
void dfs(int x, int y, int label){
if(x < 0 || x == SIZE)
return;
if(y < 0 || y == SIZE)
return;
if(data[x][y] == 0 || mark[x][y] != 0)
return;
mark[x][y] = label;
dfs(x + 1, y, label);
dfs(x, y + 1, label);
dfs(x - 1, y, label);
dfs(x, y - 1, label);
}
Please help me convert recursion to loops like for or while.
Thank you all in advance.
You can make a new structure and use stack. make_tuple(int x,int y,int label) returns tuple type.
typedef struct
{
int x,y,label;
} tuple;
stack<tuple > s;
s.push(make_tuple(initialx,initialy,initiallabel));
while(!s.empty())
{
tuple p = s.top();
s.pop();
int x = p.x;
int y = p.y;
int label = p.label;
if(x < 0 || x == SIZE)
continue;
if(y < 0 || y == SIZE)
continue;
if(data[x][y] == 0 || mark[x][y] != 0)
continue;
mark[x][y] = label;
s.push(make_tuple(x + 1, y, label));
s.push(make_tuple(x, y + 1, label));
s.push(make_tuple(x - 1, y, label));
s.push(make_tuple(x, y - 1, label));
}

Breadth first iteration?

If we wish to cover a search space, like say for all triplets (x, y, z), where x, y, and z are between 1 and n, we can use nested looping to do this:
for (int x = 1; x <= n; x++)
for (int y = 1; y <= n; y++)
for (int z = 1; z <= n; z++)
This generates triplets: (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 1, 4), etc..., and is effectively a "depth first search" or depth first iteration.
Is there a way to iterate in a more "breadth first" fashion? Such an iteration would generate triplets in an order similar to:
(1, 1, 1), (2, 1, 1), (1, 2, 1), (1, 1, 2), (2, 2, 1), (2, 1, 2), (1, 2, 2), (2, 2, 2), (3, 1, 1), etc...
and is there also a name for the algorithm that would generate such a pattern?
This C# code generates the pattern I described, and in a good order, but I have a feeling there is a better way to do it.
void Visit(ISet<Tuple<int, int, int>> pSet, int pX, int pY, int pZ) {
var value = Tuple.Create(pX, pY, pZ);
if (pSet == null)
Console.WriteLine(value);
else if (!pSet.Contains(value)){
pSet.Add(value);
Console.WriteLine(value);
}
}
void Iterate() {
const int n = 5;
for (int x = 1; x <= n; x++) {
var set = new HashSet<Tuple<int, int, int>>();
for (int y = 1; y <= x; y++)
for (int z = 1; z <= y; z++) {
Visit(set, z, y, x);
Visit(set, z, x, y);
Visit(set, y, z, x);
Visit(set, y, x, z);
Visit(set, x, z, y);
Visit(set, x, y, z);
}
}
}
This code generates the pattern without maintaining any lists or doing any collision checking. I've confirmed that it generates n³ tuples with no duplicates (up to n=500). The only issue is that this only works for the specific case of iterating over 3-tuples of ints, rather than any number of any type of collections.
static void Iterate() {
const int n = 500;
for (int x = 1; x <= n; x++) {
for (int y = 1; y <= x; y++)
for (int z = 1; z <= y; z++) {
Visit(z, y, x);
if (x == y && y == z && x == z)
continue;
if (x != y)
Visit(z, x, y);
if (z != y) {
Visit(y, z, x);
Visit(y, x, z);
}
if (x != y && x != z) {
Visit(x, z, y);
if (z != y)
Visit(x, y, z);
}
}
}
}
This should work.
for (int x = 1; x <= n; x++)
for (int y = 1; y <= n; y++)
{
for (int z = 1; z <= n; z++)
{
enqueue(the x-y-z triplet);
}
print(till the queue empties);
}
Sorry for my pseudo-C.

Resources