Count of Possible paths of given Matrix having Bitwise XOR equal to K
Given an N*M (N + M ≤ 40)matrix mat[][], each cell has some value ranging from 0 to 1018 and an integer K. Find the count of all possible paths such that bitwise XOR of elements in a path is equal to K. Movement is allowed only in the right and downward direction.
Examples:
Input: N = 3, M = 4, K= 2
mat[][] = { {1, 3, 3, 3},
{0, 3, 3, 2},
{3, 0, 1, 1} }
Output: 5
Explanation: All possible paths are:
(1,1)→(2,1)→(2,2)→(3,2)→(3,3)→(3,4) = 1^0 ^3^0^1^1 = 2
(1,1)→(2,1)→(3,1)→(3,2)→(3,3)→(3,4) = 1^0^3^0^1^1 = 2
(1,1)→(2,1)→(2,2)→(2,3)→(2,4)→(3,4) = 1^0^3^3^2^1 =2
(1,1)→(1,2)→(1,3)→(2,3)→(3,3)→(3,4) = 1^3^3^3^1^1 =2
(1,1)→(1,2)→(2,2)→(2,3)→(3,3)→(3,4) = 1^3^3^3^1^1 =2Input: N = 3, M = 3, K =11
mat[][] = { {2, 1, 5},
{7, 10, 0},
{12, 6, 4} }
Output: 3
Explanation:All possible paths are:
(1,1)→(2,1)→(3,1)→(3,2)→(3,3) = 2 ^ 7 ^12 ^ 6 ^4 =11
(1,1)→(2,1)→(2,2)→(2,3)→(3,3) = 2 ^ 7 ^ 10 ^ 0 ^4 =11
(1,1)→(1,2)→(2,2)→(3,2)→(3,3) = 2^1^10^ 6 ^ 4 = 11
Naive Approach: The simple approach is to travel all possible paths and check if the XOR of that path is equal to K or not. In this, use backtracking as at any given cell there will be two choices either to go right or down and this would become two recursive statements in backtracking solution.
Below is the implementation of the above approach :
C++
// C++ code to implement the above approach #include <bits/stdc++.h> using namespace std; #define ll long long int ll n, m, k; vector<vector<ll>> mat; // Backtracking to find the path count void backtracking(ll i, ll j, ll zor, ll &ans) { // If the bottom-right cell is reached if (i == n - 1 && j == m - 1) { // If XOR value is k if (zor == k) ans++; return ; } // Move rightwards if (j + 1 < m) backtracking(i, j + 1, zor ^ mat[i][j + 1], ans); // Move downwards if (i + 1 < n) backtracking(i + 1, j, zor ^ mat[i + 1][j], ans); } // Function to calculate all possible paths int countPaths( int N, int M, int K) { ll ans = 0; n = N; m = M; k = K; if (N == 1 && M == 1 && mat[0][0] == K) { return 1; } // Calling the backtracking function backtracking(0, 0, mat[0][0], ans); return ans; } // Driver Code int main() { int N = 3, M = 3, K = 11; mat = { {2, 1, 5}, {7, 10, 0}, {12, 6, 4} }; // Function call int ans = countPaths(N, M, K); cout << ans << "\n" ; return 0; } |
Java
// Java code to implement the above approach import java.util.*; class GFG{ static int n, m, k , ans; static int [][]mat; // Backtracking to find the path count static void backtracking( int i, int j, int zor) { // If the bottom-right ceint is reached if (i == n - 1 && j == m - 1 ) { // If XOR value is k if (zor == k) ans++; return ; } // Move rightwards if (j + 1 < m) backtracking(i, j + 1 , zor ^ mat[i][j + 1 ]); // Move downwards if (i + 1 < n) backtracking(i + 1 , j, zor ^ mat[i + 1 ][j]); } // Function to calculate all possible paths static int countPaths( int N, int M, int K) { ans = 0 ; n = N; m = M; k = K; if (N == 1 && M == 1 && mat[ 0 ][ 0 ] == K) { return 1 ; } // Calling the backtracking function backtracking( 0 , 0 , mat[ 0 ][ 0 ]); return ans; } // Driver Code public static void main(String[] args) { int N = 3 , M = 3 , K = 11 ; mat = new int [][]{ { 2 , 1 , 5 }, { 7 , 10 , 0 }, { 12 , 6 , 4 } }; // Function call int ans = countPaths(N, M, K); System.out.print(ans+ "\n" ); } } // This code is contributed by 29AjayKumar |
Python3
# Python program to find maximum sum in Binary Tree mat = [[ 0 for i in range ( 2 )] for j in range ( 2 )] n,m,k,ans = 0 , 0 , 0 , 0 # Backtracking to find the path count def backtracking(i, j, zor): global ans # If the bottom-right ceis reached if (i = = n - 1 and j = = m - 1 ): # If XOR value is k if (zor = = k): ans + = 1 return # Move rightwards if (j + 1 < m): backtracking(i, j + 1 ,zor ^ mat[i][j + 1 ]) # Move downwards if (i + 1 < n): backtracking(i + 1 , j,zor ^ mat[i + 1 ][j]) # Function to calculate all possible paths def countPaths(N, M, K): global n,m,k,ans ans = 0 n,m,k = N,M,K if (N = = 1 and M = = 1 and mat[ 0 ][ 0 ] = = K): return 1 # Calling the backtracking function backtracking( 0 , 0 , mat[ 0 ][ 0 ]) return ans # Driver Code N,M,K = 3 , 3 , 11 mat = [ [ 2 , 1 , 5 ], [ 7 , 10 , 0 ], [ 12 , 6 , 4 ]] # Function call anss = countPaths(N, M, K) print (anss) # This code is contributed by shinjanpatra |
C#
// C# code to implement the above approach using System; class GFG{ static int n, m, k, ans; // Backtracking to find the path count static void backtracking( int i, int j, int zor, int [,]mat) { // If the bottom-right ceint is reached if (i == n - 1 && j == m - 1) { // If XOR value is k if (zor == k) ans++; return ; } // Move rightwards if (j + 1 < m) backtracking(i, j + 1, zor ^ mat[i, j + 1], mat); // Move downwards if (i + 1 < n) backtracking(i + 1, j, zor ^ mat[i + 1, j], mat); } // Function to calculate all possible paths static int countPaths( int N, int M, int K, int [,]mat) { ans = 0; n = N; m = M; k = K; if (N == 1 && M == 1 && mat[0, 0] == K) { return 1; } // Calling the backtracking function backtracking(0, 0, mat[0, 0], mat); return ans; } // Driver Code public static void Main() { int N = 3, M = 3, K = 11; int [,]mat = { {2, 1, 5}, {7, 10, 0}, {12, 6, 4} }; // Function call int ans = countPaths(N, M, K, mat); Console.Write(ans+ "\n" ); } } // This code is contributed by Samim Hossain Mondal. |
Javascript
<script> // JavaScript program to implement above approach let n, m, k , ans; var mat = new Array(2); // Loop to create 2D array using 1D array for ( var i = 0; i < mat.length; i++) { mat[i] = new Array(2); } // Backtracking to find the path count function backtracking(i, j, zor) { // If the bottom-right celet is reached if (i == n - 1 && j == m - 1) { // If XOR value is k if (zor == k) ans++; return ; } // Move rightwards if (j + 1 < m) backtracking(i, j + 1, zor ^ mat[i][j + 1]); // Move downwards if (i + 1 < n) backtracking(i + 1, j, zor ^ mat[i + 1][j]); } // Function to calculate all possible paths function countPaths(N, M, K) { ans = 0; n = N; m = M; k = K; if (N == 1 && M == 1 && mat[0][0] == K) { return 1; } // Calling the backtracking function backtracking(0, 0, mat[0][0]); return ans; } // Driver Code let N = 3, M = 3, K = 11; mat = [ [2, 1, 5], [7, 10, 0], [12, 6, 4]]; // Function call let anss = countPaths(N, M, K); document.write(anss); // This code iscontributed by sanjoy_62. </script> |
3
Time Complexity: O(2X * X) where X = (N + M – 2)
Auxiliary Space: O(1)
Why simply Backtracking would fail here?
The number of moves required to move from (1, 1) to (N, M) will be equal to (N+M-2). Now, using a recursive backtracking solution It will take O(2(N+M-2)) time to iterate over all the paths of this length and check if each path is having XOR equal to K or not. For higher values of (N+M) this algorithm becomes very time consuming as the value reaches close to the constraint provided here.
Efficient Approach: Using Meet in The Middle Algorithm split the number of steps and make (N + M – 2)/2 in the first half, rest steps in the next half. Follow the steps mentioned below to solve the problem:
- And combine the answers of the two solutions, which is basically the standard idea of the Meet in the Middle Algorithm.
- Split this mask of n+m−2 bits into two parts, mid=(n+m−2)/2 bits and (n+m−2)−mid bits.
- For The Left Part:
- Perform recursive backtracking starting from the cell (1,1) and to the bottom and maintain xor of the path for mid steps. after mid steps, we have the index position i.e. (i,j) and the xor value up to this point, and calculate how many such triplets exits {zor, i,j}
- For The Right Part:
- Perform recursive backtracking starting from the cell (N, M) and to the left or to the upwards and maintain xor of the path for
(N+M-2) – mid -1 steps.
- Perform recursive backtracking starting from the cell (N, M) and to the left or to the upwards and maintain xor of the path for
- after mid steps in, the index position i.e. (i,j) is found and the xor value up to this point, and calculate how many such triplets exits {zor, i,j}
- After writing code for both parts now traverse the triplets of the second part and check if in one step i.e (i-1,j) or (j-1, i) we have a triplet having xor K in triplets of the left part.
Below is the implementation of the above approach:
C++14
// C++ code to implement the above approach #include <bits/stdc++.h> using namespace std; #define ll long long int ll n, m, k; vector<vector<ll>> a; ll cnt1 = 0, cnt2 = 0; map<pair<ll, pair<ll, ll> >, ll> mp1, mp2; // Backtracking function for the left part void part1(ll i, ll j, ll cnt, ll zor) { if (cnt <= 0) { // Count the number of triplets mp1[{ zor, { i, j } }]++; return ; } // Move rightwards if (j + 1 < m) { part1(i, j + 1, cnt - 1, zor ^ a[i][j + 1]); } // Move downwards if (i + 1 < n) part1(i + 1, j, cnt - 1, zor ^ a[i + 1][j]); } // Backtracking function for the right part void part2(ll i, ll j, ll cnt, ll zor) { if (cnt <= 0) { // Count the number of triplets mp2[{ zor, { i, j } }]++; return ; } // Move leftwards if (j - 1 >= 0) { part2(i, j - 1, cnt - 1, zor ^ a[i][j - 1]); } // Move upwards if (i - 1 >= 0) part2(i - 1, j, cnt - 1, zor ^ a[i - 1][j]); } // Function to count the paths with xor K int countPaths( int N, int M, int K) { ll ans = 0; n = N; m = M; k = K; // Number of steps for left part cnt1 = (n + m - 2) / 2; // NUmber of steps for right part cnt2 = (n + m - 2) - cnt1; // number of steps in both parts are 0 if (n == 1 && m == 1 && a[0][0] == k) { return 1; } // Calling the recursive function // for the left and right part part1(0, 0, cnt1, a[0][0]); part2(n - 1, m - 1, cnt2 - 1, a[n - 1][m - 1]); // mp2 contains triplet of right part so // traverse the triplets of right part for ( auto i : mp2) { // Extracting all elements // from the triplet ll zor = i.first.first; ll idx = i.first.second.first; ll j = i.first.second.second; ll cnt = i.second; // XOR OF RIGHT SIDE IS zor , // then Xor of left side // must be zor^k such that Xor // of the total path is K ll required = k ^ zor; // Checking if one index to the left // are left triplet as how many paths if ((idx - 1) >= 0 && mp1.find({ required, { idx - 1, j } }) != mp1.end()) { // Total path would be paths // in left * paths in right ans += (cnt * mp1[{ required, { idx - 1, j } }]); } // Checking if one index upwards // are left triplet as how many paths if ((j - 1) >= 0 && mp1.find({ required, { idx, j - 1 } }) != mp1.end()) { // Total path would be paths // in left * paths in right ans += (cnt * mp1[{ required, { idx, j - 1 } }]); } } return ans; } // Driver Code int main() { int N = 3, M = 3, K = 11; a = { {2, 1, 5}, {7, 10, 0}, {12, 6, 4} }; int ans = countPaths(N, M, K); cout << ans; return 0; } |
Python3
from typing import List , Tuple from collections import defaultdict def count_paths(n: int , m: int , k: int , a: List [ List [ int ]]) - > int : # cnt1: number of steps in left part # cnt2: number of steps in right part cnt1 = (n + m - 2 ) / / 2 cnt2 = (n + m - 2 ) - cnt1 # Edge case: matrix is 1x1 and the only element is k if n = = 1 and m = = 1 and a[ 0 ][ 0 ] = = k: return 1 mp1 = defaultdict( int ) # left part mp2 = defaultdict( int ) # right part # Recursive function for left part def part1(i: int , j: int , cnt: int , zor: int ) - > None : if cnt < = 0 : # Count the number of triplets mp1[(zor, (i, j))] + = 1 return # Move rightwards if j + 1 < m: part1(i, j + 1 , cnt - 1 , zor ^ a[i][j + 1 ]) # Move downwards if i + 1 < n: part1(i + 1 , j, cnt - 1 , zor ^ a[i + 1 ][j]) # Recursive function for right part def part2(i: int , j: int , cnt: int , zor: int ) - > None : if cnt < = 0 : # Count the number of triplets mp2[(zor, (i, j))] + = 1 return # Move leftwards if j - 1 > = 0 : part2(i, j - 1 , cnt - 1 , zor ^ a[i][j - 1 ]) # Move upwards if i - 1 > = 0 : part2(i - 1 , j, cnt - 1 , zor ^ a[i - 1 ][j]) # Call the recursive functions for left and right parts part1( 0 , 0 , cnt1, a[ 0 ][ 0 ]) part2(n - 1 , m - 1 , cnt2 - 1 , a[n - 1 ][m - 1 ]) ans = 0 # Iterate through the triplets in the right part for zor, (idx, j), cnt in mp2.items(): # XOR of right side is zor, XOR of left side must be zor^k # such that XOR of the total path is K required = k ^ zor # Check if there is a left triplet one index to the left if idx - 1 > = 0 and (required, (idx - 1 , j)) in mp1: # Total path is paths in left * paths in right ans + = cnt * mp1[(required, (idx - 1 , j))] # Check if there is a left triplet one index upwards if j - 1 > = 0 and (required, (idx, j - 1 )) in mp1: |
3
Time Complexity: O(X * 2X) where X = (N + M – 2)/2
Auxiliary Space: O(N + M)
Please Login to comment...