package com.anuragkapur.ada1; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; /** * Count number of split inversions in an array * * @author anuragkapur */ public class CountInversions { static int a[] = new int[100000]; /** * Assumes the 2 parts of the array are sorted, and merges them. While merging, count split inversions * * @param start * @param end * @param leftStart * @param leftEnd * @param rightStart * @param rightEnd * @return */ public static long countSplitInversionsAndMerge(int start, int end, int leftStart, int leftEnd, int rightStart, int rightEnd) { int subArray1[] = new int[leftEnd - leftStart + 1]; int subArray2[] = new int[rightEnd - rightStart + 1]; int count = 0; for (int i = leftStart; i <= leftEnd; i++) { subArray1[count++] = a[i]; } count = 0; for (int i = rightStart; i <= rightEnd; i++) { subArray2[count++] = a[i]; } // merge and count inversions int leftPointer = 0, rightPointer = 0; long inversions = 0; for (int i = start; i <= end; i++) { if(leftPointer >= subArray1.length) { a[i] = subArray2[rightPointer++]; }else if(rightPointer >= subArray2.length) { a[i] = subArray1[leftPointer++]; }else if (subArray1[leftPointer] <= subArray2[rightPointer]) { a[i] = subArray1[leftPointer++]; }else if(subArray1[leftPointer] > subArray2[rightPointer]) { for (int j = leftPointer; j < subArray1.length; j++) { //System.out.println(subArray1[j] + "," + subArray2[rightPointer]); } a[i] = subArray2[rightPointer++]; inversions = inversions + subArray1.length - leftPointer; } } return inversions; } /** * Recursive method to count left and right inversions * * @param start * @param end * @return */ public static long countInversionsAndSort(int start, int end) { //System.out.println("start :: " + start + " end :: " + end); if(end - start == 1) { // two elements in array, just sort them and return if this is an inversion if (a[start] > a[end]) { int temp = a[start]; a[start] = a[end]; a[end] = temp; return 1; }else { return 0; } }else if(end == start) { // one element in array, no sorting required, can be a left / right inversion return 0; }else { int leftStart = start; int leftEnd = ((end - start) / 2 ) + start; int rightStart = ((end - start) / 2 ) + start +1; int rightEnd = end; long leftInversions = countInversionsAndSort(leftStart, leftEnd); long rightInversions = countInversionsAndSort(rightStart, rightEnd); long splitInversions = countSplitInversionsAndMerge(start, end, leftStart, leftEnd, rightStart, rightEnd); return leftInversions + rightInversions + splitInversions; } } /** * @param args */ public static void main(String[] args) { File inputFile = new File("src/com/anuragkapur/ada1/countinversions.in"); String inputFilePath = inputFile.getAbsolutePath(); // read and parse input file try { String strLine = ""; int count = 0; FileInputStream fstream = new FileInputStream(inputFilePath); DataInputStream in = new DataInputStream(fstream); BufferedReader br = new BufferedReader(new InputStreamReader(in)); while ((strLine = br.readLine()) != null) { a[count ++] = Integer.parseInt(strLine); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } System.out.println(countInversionsAndSort(0, a.length-1)); } }