Open In App

Find expected swaps to sort given Array where probability of swapping any inversion pair is equal

Improve
Improve
Like Article
Like
Save
Share
Report

Given an array arr[] consisting of permutation of the first N natural numbers, the task is to find the expected number of swaps to sort the given array where the probability of swapping any inversion pair is equal and the probability of swapping any non-inversion pair is 0.

Examples:

Input: arr[] = {3, 2, 1}
Output: 2.3333
Explanation: The given array can be sorted in non-decreasing order using sequences of swaps as shown in the image below. 
 

The expected numbers of swaps of each node can be calculated by 1 + (average of expected number of swaps of all the child nodes). 
Since the nodes 3, 9, 10, 11, and 12 are already sorted, the number of expected swaps to sort them are 0.
The expected number of swaps of nodes 5, 6, 7, and 8 will be 1.
Similarly, the expected number of swaps of nodes 2 and 4 will be 2.
Hence, the expected number of swaps of node 1 is 1 + (2 + 2 + 0)/3 = 1 + 1.3333 = 2.3333

Input: arr[] = {1, 3, 2}
Output: 1.0
Explanation: Since there is only 1 inversion pair (arr[1], arr[2]), the expected number of swaps is 1.

 

Approach: The given problem can be solved with the help of Recursion and Backtracking using Memoization which is based on the following observations:

  • An inversion in the array is defined as two indices (i, j) such that i < j and arr[i] > arr[j]. The expected number of swaps can be calculated recursively after swapping the integers of each valid inversion one at a time and recursively calling for the permutation after the swap until the whole permutation is sorted.
  • Suppose there are K inversions in the current permutation and after swapping the ith inversion, the expected number of swaps to sort the permutation is denoted by Pi. Therefore, the expected number of swaps after swapping all possible inversions will be (P1 + P2 + … + PK)/K.

Using the above observations, the given problem can be solved by the following steps:

  • Create a map, say memo that stores the expected number of swaps for a given permutation.
  • Create a Recursive Function expectedSwaps(), which takes a permutation as an argument and returns the expected number of swaps.
  • In the expectedSwaps() function, if the expected swaps of the current permutation are already calculated, return the answer. Otherwise, iterate over each valid inversion and swap the index of the current inversion and recursively call for the permutation after swapping.
  • Find the sum of the expected swaps after each valid swap in a variable, say res, and the count of inversions in a variable, say K.
  • After completing the above steps, print the value of res / K as the result.

Below is the implementation of the above approach:

C++




// C++ program for the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Stores result of each state of the
// array in a memoization table
map<vector<int>, double> memo;
 
// Recursive function to find expected
// number of swaps to sort given array
double expectedSwaps(vector<int> a)
{
    // The value for the given permutation
    // is already calculated
    if (memo.count(a)) {
        return memo[a];
    }
 
    // Stores the expected number of ways
    double res = 0;
 
    // Stores the total operations done
    int K = 0;
 
    // Iterate for all possible pairs of
    // Inversions
    for (int i = 0; i < a.size(); i++) {
        for (int j = i + 1; j < a.size(); j++) {
 
            // For the current inversion
            // find the expected value
            if (a[i] > a[j]) {
                swap(a[i], a[j]);
 
                // Recursively Call
                res += 1 + expectedSwaps(a);
 
                // Backtrack
                swap(a[i], a[j]);
                K++;
            }
        }
    }
 
    // If permutation is already sorted
    if (K == 0)
        res = 0;
 
    // Calculate expected swaps for
    // current permutation
    else
        res /= K;
 
    // Return answer
    return memo[a] = res;
}
 
// Driver Code
int main()
{
    int N = 3;
    vector<int> arr = { 3, 2, 1 };
 
    cout << expectedSwaps(arr);
 
    return 0;
}


Java




// Java code for the above approach:
import java.util.*;
 
public class Main
{
   
    // Stores result of each state of the
    // array in a memoization table
    static HashMap <ArrayList <Integer>, Double> memo;
 
    // Recursive function to find expected
    // number of swaps to sort given array
    static double expectedSwaps(ArrayList <Integer> a)
    {
       
        // The value for the given permutation
        // is already calculated
        if (memo.containsKey(a)) {
            return memo.get(a);
        }
 
        // Stores the expected number of ways
        double res = 0;
 
        // Stores the total operations done
        int K = 0;
 
        // Iterate for all possible pairs of
        // Inversions
        for (int i = 0; i < a.size(); i++) {
            for (int j = i + 1; j < a.size(); j++) {
 
                // For the current inversion
                // find the expected value
                if (a.get(i) > a.get(j)) {
                    Collections.swap(a, i, j);
 
                    // Recursively Call
                    res += 1 + expectedSwaps(a);
 
                    // Backtrack
                    Collections.swap(a, i, j);
                    K++;
                }
            }
        }
 
        // If permutation is already sorted
        if (K == 0)
            res = 0;
 
        // Calculate expected swaps for
        // current permutation
        else
            res /= K;
 
        // Return answer
        memo.put(a,res);
        return res;
    }
 
    // Driver Code
    public static void main(String args[]) {
        int N = 3;
        ArrayList <Integer> arr
                    = new ArrayList <Integer> (Arrays.asList( 3, 2, 1 ));
        memo = new HashMap <ArrayList <Integer>, Double> ();
        // Function calling
        System.out.println( expectedSwaps(arr) );
    }
}
 
// This code has been contributed by Sachin Sahara (sachin801)


Python3




# Python program for the above approach
# Stores result of each state of the
# array in a memoization table
memo = {}
 
# Recursive function to find expected
# number of swaps to sort given array
def expectedSwaps(a):
   
  # The value for the given permutation
  # is already calculated
  if (tuple(a) in memo):
    return memo[tuple(a)]
   
  # Stores the expected number of ways
  res = 0
 
  # Stores the total operations done
  K = 0
 
  # Iterate for all possible pairs of
  # Inversions
  for i in range(len(a)):
    for j in range(i + 1,len(a)):
       
      # For the current inversion
      # find the expected value
      if (a[i] > a[j]):
        temp = a[i]
        a[i] = a[j]
        a[j] = temp
         
        # Recursively Call
        res += 1 + expectedSwaps(a)
         
        #Backtrack
        temp = a[i]
        a[i] = a[j]
        a[j] = temp
        K += 1
         
  # If permutation is already sorted
  if (K == 0):
    res = 0
 
  # Calculate expected swaps for
  # current permutation
  else:
    res /= K;
 
  # Return answer
  memo[tuple(a)] = res
  return res
 
# Driver Code
N = 3
arr = [ 3, 2, 1 ]
print(expectedSwaps(arr))
 
# This code is contributed by rohitsingh07052.


Javascript




<script>
// JavaScript program for the above approach
// Stores result of each state of the
// array in a memoization table
 
var dict = {};
 
// Recursive function to find expected
// number of swaps to sort given array
function expectedSwaps(a)
{
 
  // The value for the given permutation
  // is already calculated
  if (dict.hasOwnProperty(a)) {
    return dict[a];
  }
   
  // Stores the expected number of ways
  var res = 0;
   
  // Stores the total operations done
  var K = 0;
 
  // Iterate for all possible pairs of
  // Inversions
  for (let i = 0; i < a.length; i++)
  {
    for (let j = i + 1; j < a.length; j++)
    {
     
      // For the current inversion
      // find the expected value
      if (a[i] > a[j]) {
        var temp = a[i];
        a[i] = a[j];
        a[j] = temp;
 
        // Recursively Call
        res += 1 + expectedSwaps(a);
         
        // Backtrack
        var temp2 = a[i];
        a[i] = a[j];
        a[j] = temp2;
        K++;
      }
    }
  }
 
  // If permutation is already sorted
  if (K == 0) {
    res = 0;
  }
   
  // Calculate expected swaps for
  // current permutation
  else {
    res /= K;
  }
 
  // Return answer
  dict[a] = res;
  return res;
}
 
// Driver Code
var N = 3;
var arr = [3, 2, 1];
document.write(expectedSwaps(arr).toFixed(5));
 
// This code is contributed by rdtank.
</script>


C#




// C# program to implement above approach
using System;
using System.Collections.Generic;
 
class GFG
{
 
    // Stores result of each state of the
    // array in a memoization table
    public static Dictionary<List<int>, double> memo = new Dictionary<List<int>, double>();
 
    public static bool checkEquality(List<int> a,List<int> b){
        if(a.Count != b.Count) return false;
        for(int i = 0 ; i < a.Count ; i++){
            if(a[i]!=b[i]) return false;
        }
        return true;
    }
 
    public static double containsKey(List<int> a){
        foreach(KeyValuePair<List<int>,double> x in memo){
            if(checkEquality(a, x.Key)){
                return x.Value;
            }
        }
        return -1;
    }
 
    // Recursive function to find expected
    // number of swaps to sort given array
    public static double expectedSwaps(List<int> a)
    {
        // The value for the given permutation
        // is already calculated
        double res = containsKey(a);
        if (res != -1) {
            return res;
        }
 
        // Stores the expected number of ways
        res = 0;
 
        // Stores the total operations done
        int K = 0;
 
        // Iterate for all possible pairs of
        // Inversions
        for (int i = 0 ; i < a.Count ; i++) {
            for (int j = i + 1 ; j < a.Count ; j++) {
                 
 
                // For the current inversion
                // find the expected value
                if (a[i] > a[j]) {
                    int temp = a[i];
                    a[i] = a[j];
                    a[j] = temp;
 
                    // Recursively Call
                    res += 1 + expectedSwaps(a);
 
                    // Backtrack
                    temp = a[i];
                    a[i] = a[j];
                    a[j] = temp;
                     
                    K++;
                }
            }
        }
 
        // If permutation is already sorted
        if (K == 0)
            res = 0;
 
        // Calculate expected swaps for
        // current permutation
        else
            res = res/(double)K;
 
        // for(int i=0 ; i<a.Count ; i++){
        //     Console.Write(a[i] + " ");
        // }
        // Console.Write("\n" + res + "\n");
 
        memo[new List<int>(a)] = res;
        // Return answer
        return res;
    }
 
 
    // Driver Code
    public static void Main(string[] args){
         
        // int N = 3;
        List<int> arr = new List<int>{ 3, 2, 1 };
 
        Console.Write(expectedSwaps(arr));
 
    }
}


Output

2.33333

Time Complexity: O(N2N!)
Auxiliary Space: O(N!)



Last Updated : 02 Aug, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads