Count inversion pairs in a matrix - GeeksforGeeks

20 Mar, 2020
Given a matrix A of size NxN, we need to find the number of inversion pairs in it. Inversion count in a matrix is defined as the number of pairs satisfying the following conditions :
x1 ≤ x2
y1 ≤ y2
A[x2][y2] < A[x1][y1]
Constraints :
1 ≤ Ai,j ≤ 109
1 ≤ N ≤ 103
Examples:
For simplicity, let's take a 2x2 matrix :
A = {{7, 5},
     {3, 1}};
The inversion pairs are : (7, 5), (3, 1), (7, 3), (5, 1) and (7, 1)
Output : 5

To solve this problem, we need to know the following things :
Finding number of inversion pairs in a 1D array using Binary Indexed Tree (BIT)https://www.geeksforgeeks.org/count-inversions-array-set-3-using-bit2D BIThttps://www.geeksforgeeks.org/two-dimensional-binary-indexed-tree-or-fenwick-tree
Finding number of inversion pairs in a 1D array using Binary Indexed Tree (BIT)https://www.geeksforgeeks.org/count-inversions-array-set-3-using-bit
2D BIThttps://www.geeksforgeeks.org/two-dimensional-binary-indexed-tree-or-fenwick-tree
Since, we need to find number of inversion pairs in a matrix, first thing we need to do is to store the elements of the matrix in another array, say v and sort the array v so that we can compare the elements of the unsorted matrix with v and find the number of inversion pairs using BIT. But it is given that the values of the elements are very large (109), so we cannot use the values of the elements in the matrix as indices in the BIT. Thus, we need to use the position of the elements as indexes in the 2D BIT.We are going to use the tuple (-A[i][j], i, j) for each element of the matrix and store it in an array, say ‘v’. Then we need to sort v according to the value of -A[i][j] in ascending order, so that the largest element of the matrix will be stored at index 0 and the smallest one at the last index of v. Now, the problem is reduced to finding inversion pairs in a 1D array, the only exception is that we are going to use a 2D BIT.Note that here we are using negative values of A[i][j], simply because we are going to traverse v from left to right, i.e., from the largest number in the matrix to the smallest one(because that’s what we do when finding inversion pairs in a 1D array using BIT). One can also use positive values and traverse v from right to left fashion, final result will remain same.
Algorithm :
1. Initialize inv_pair_cnt = 0, which will store the number of inversion pairs.
2. Store the tuple (-A[i][j], i, j) in an array, say v, where A[i][j] is the
   element of the matrix A at position (i, j).
3. Sort the array v according to the first element of the tuple, i.e., 
   according to the value of -A[i][j].
4. Traverse the array v and do the following :
       - Initialize an array, say 'pairs' to store the position (i, j)
         of the tuples of v. 
       - while the current tuple of v and all its adjacent tuples whose 
         first value, i.e., -A[i][j] is same, do 
             - Push the current tuple's position pair (i, j) into 'pairs'.
             - Add to inv_pair_cnt,  the number of elements which are less than 
               the current element(i.e., A[i][j]) and lie on the right side 
               in the sorted array v, by calling the query operation of BIT and 
               passing i and j as arguments.
       - For each position pair (i, j) stored in the array 'pairs', 
         update the position (i, j) in the 2D BIT by 1.
5. Finally, inv_pair_cnt will contain the number of inversion pairs.

Here is the implementation :
C++
Python3
// C++ program to count the number of inversion// pairs in a 2D matrix#include <bits/stdc++.h>using namespace std;  // for simplicity, we are taking N as 4#define N 4  // Function to update a 2D BIT. It updates the// value of bit[l][r] by adding val to bit[l][r]void update(int l, int r, int val, int bit[][N + 1]){    for (int i = l; i <= N; i += i & -i)        for (int j = r; j <= N; j += j & -j)            bit[i][j] += val;}  // function to find cumulative sum upto// index (l, r) in the 2D BITlong long query(int l, int r, int bit[][N + 1]){    long long ret = 0;    for (int i = l; i > 0; i -= i & -i)        for (int j = r; j > 0; j -= j & -j)            ret += bit[i][j];      return ret;}  // function to count and return the number// of inversion pairs in the matrixlong long countInversionPairs(int mat[][N]){    // the 2D bit array and initialize it with 0.    int bit[N+1][N+1] = {0};      // v will store the tuple (-mat[i][j], i, j)    vector<pair<int, pair<int, int> > > v;      // store the tuples in the vector v    for (int i = 0; i < N; ++i)        for (int j = 0; j < N; ++j)              // Note that we are not using the pair            // (0, 0) because BIT update and query            // operations are not done on index 0            v.push_back(make_pair(-mat[i][j],                        make_pair(i+1, j+1)));      // sort the vector v according to the    // first element of the tuple, i.e., -mat[i][j]    sort(v.begin(), v.end());      // inv_pair_cnt will store the number of    // inversion pairs    long long inv_pair_cnt = 0;      // traverse all the tuples of vector v    int i = 0;    while (i < v.size())    {        int curr = i;          // 'pairs' will store the position of each element,        // i.e., the pair (i, j) of each tuple of the vector v        vector<pair<int, int> > pairs;          // consider the current tuple in v and all its        // adjacent tuples whose first value, i.e., the        // value of –mat[i][j] is same        while (curr < v.size() &&               (v[curr].first == v[i].first))        {            // push the position of the current element in 'pairs'            pairs.push_back(make_pair(v[curr].second.first,                                      v[curr].second.second));              // add the number of elements which are            // less than the current element and lie on the right            // side in the vector v            inv_pair_cnt += query(v[curr].second.first,                                  v[curr].second.second, bit);              curr++;        }          vector<pair<int, int> >::iterator it;          // traverse the 'pairs' vector        for (it = pairs.begin(); it != pairs.end(); ++it)        {            int x = it->first;            int y = it->second;              // update the position (x, y) by 1            update(x, y, 1, bit);        }          i = curr;    }      return inv_pair_cnt;}  // Driver programint main(){    int mat[N][N] = { { 4, 7, 2, 9 },                      { 6, 4, 1, 7 },                      { 5, 3, 8, 1 },                      { 3, 2, 5, 6 } };      long long inv_pair_cnt = countInversionPairs(mat);      cout << "The number of inversion pairs are : "         << inv_pair_cnt << endl;      return 0;}
# Python3 program to count the number of inversion# pairs in a 2D matrix  # for simplicity, we are taking N as 4N = 4  # Function to update a 2D BIT. It updates the# value of bit[l][r] by adding val to bit[l][r]def update(l, r, val, bit):    i = l    while(i <= N):        j = r        while(j <= N):             bit[i][j] += val            j += j & -j        i += i & -i  # function to find cumulative sum upto# index (l, r) in the 2D BITdef query(l, r, bit):    ret = 0    i = l    while(i > 0):        j = r        while(j > 0):            ret += bit[i][j]            j -= j & -j        i -= i & -i          return ret  # function to count and return the number# of inversion pairs in the matrixdef countInversionPairs(mat):          # the 2D bit array and initialize it with 0.    bit = [[0 for i in range(N + 1)] for j in range(N + 1)]          # v will store the tuple (-mat[i][j], i, j)    v = []          # store the tuples in the vector v    for i in range(N):        for j in range(N):                          # Note that we are not using the pair            # (0, 0) because BIT update and query            # operations are not done on index 0            v.append([-mat[i][j], [i + 1, j + 1]])          # sort the vector v according to the    # first element of the tuple, i.e., -mat[i][j]    v.sort()          # inv_pair_cnt will store the number of    # inversion pairs    inv_pair_cnt = 0          # traverse all the tuples of vector v    i = 0    while (i < len(v)):                  curr = i                  # 'pairs' will store the position of each element,        # i.e., the pair (i, j) of each tuple of the vector v        pairs = []                  # consider the current tuple in v and all its        # adjacent tuples whose first value, i.e., the        # value of –mat[i][j] is same        while (curr < len(v) and (v[curr][0] == v[i][0])):                          # push the position of the current element in 'pairs'            pairs.append([v[curr][1][0], v[curr][1][1]])                          # add the number of elements which are            # less than the current element and lie on the right            # side in the vector v            inv_pair_cnt += query(v[curr][1][0], v[curr][1][1], bit)            curr += 1                      # traverse the 'pairs' vector        for it in pairs:            x = it[0]            y = it[1]                          # update the position (x, y) by 1            update(x, y, 1, bit)                      i = curr          return inv_pair_cnt  # Driver codemat = [[4, 7, 2, 9 ],[ 6, 4, 1, 7 ],        [ 5, 3, 8, 1 ],[3, 2, 5, 6]]  inv_pair_cnt = countInversionPairs(mat)  print("The number of inversion pairs are :", inv_pair_cnt)  # This code is contributed by shubhamsingh10
The number of inversion pairs are : 43

Time Complexity : O(log(NxN)), where N is the size of the matrixSpace Complexity : O(NxN)
This article is contributed by Avinash Kumar Saw. If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
Vijay Sirra
SHUBHAMSINGH10
Binary Indexed Tree
Advanced Data Structure
Matrix
Matrix
Binary Indexed Tree
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Comments
Old Comments
Proof that Dominant Set of a Graph is NP-Complete
2-3 Trees | (Search, Insert and Deletion)
Extendible Hashing (Dynamic approach to DBMS)
Cartesian Tree
Advantages of Trie Data Structure
Matrix Chain Multiplication | DP-8
Program to find largest element in an array
Print a given matrix in spiral form
Sudoku | Backtracking-7
Divide and Conquer | Set 5 (Strassen's Matrix Multiplication)