4

Given 2 arrays of integers a[] and b[] with the same size of n (1 <= n <= 100) numbered from 1 to n.

(0 <= a[i], b[i] <= 6)

You can swap any a[i] with b[i].

What is the minimum number of swaps needed so that the difference of the sums of array a[] and b[] is minimum ?

Then print out:

  • The number of swaps
  • The swapped indexes
  • The difference of sums of both arrays

Example

n = 6

a[] = { 1, 1, 4, 4, 0, 6 }

b[] = { 6, 3, 1, 1, 6, 1 }

Result

 - 2 (The number of swaps)
 - 5, 6 (The swapped indexes)
 - 0 (The difference of sums of the arrays)

Explanation

If you swap a[5] with b[5] and a[6] with b[6] which requires 2 swaps, arrays a[] and b[] will become:

a[] = {1, 1, 4, 4, 6, 1}

b[] = {6, 3, 1, 1, 0, 6}

Sum of a[] is 1 + 1 + 4 + 4 + 6 + 1 = 17

Sum of b[] is 6 + 3 + 1 + 1 + 0 + 6 = 17

So the difference of the two sums is 0.

unglinh279
  • 675
  • 4
  • 24
  • None of this is specific to C or C++, so I removed the tags. BTW: Read the description of tags before you apply them, there's a note concerning the use of these two in one question! – Ulrich Eckhardt Sep 26 '20 at 15:31
  • 1
    You didn't ask about efficiency but as stated this is NP-hard. Given an instance of the partition problem, put all the elements of the set to be partitioned in a[] and set b[] to all zeroes. If the set can be partitioned then the difference of the two sums will be zero and the non-zero elements in a[] and b[] give the partition. I would approach this with dynamic programming. See, e.g. https://www.ijcai.org/Proceedings/09/Papers/096.pdf – JimD. Sep 27 '20 at 23:50
  • Note that @JimD.'s observation also works the other way around. We can preprocess both arrays so that every `b[i]` is 0 without changing the problem (i.e., `a[i] = a[i] - b[i]`). Now we are just left with the well-known problem of partitioning set `a` into two parts so that the difference of their sums is minimal. The only catch here is that we do not want any solution with minimum difference but the one that also maximizes the size difference between the sets, but that doesn't change the overall approach. – Vincent van der Weele Sep 28 '20 at 06:28
  • @Vincent van der Weele i forgot to mention that the swap indexes doesn't have to be next to each other – unglinh279 Sep 28 '20 at 10:42

2 Answers2

2

Here's an iterative method that saves the differences so far and updates the smallest list of indexes needed to swap to achieve them.

JavaScript code:

function update(obj, d, arr){
  if (!obj[d] || obj[d].length > arr.length)
    obj[d] = arr;
}

function f(A, B){
  let diffs = {0: []};
  
  for (let i=0; i<A.length; i++){
    const newDiffs = {};
    
    for (d in diffs){
      // Swap
      let d1 = Number(d) + B[i] - A[i];
      if (diffs.hasOwnProperty(d1) && diffs[d1].length < diffs[d].length + 1)
        update(newDiffs, d1, diffs[d1]);
      else
        update(newDiffs, d1, diffs[d].concat(i+1));
        
      d1 = Number(d) + A[i] - B[i];
      if (diffs.hasOwnProperty(d1) && diffs[d1].length < diffs[d].length)
        update(newDiffs, d1, diffs[d1]);
      else
        update(newDiffs, d1, diffs[d]);
    }
    
    diffs = newDiffs;
  }

  console.log(JSON.stringify(diffs) + '\n\n');
  
  let best = Infinity;
  let idxs;

  for (let d in diffs){
    const _d = Math.abs(Number(d));
    if (_d < best){
      best = _d;
      idxs = diffs[d];
    }
  }

  return [best, idxs];
};

var A = [1, 1, 4, 4, 0, 6];
var B = [6, 3, 1, 1, 6, 1];

console.log(JSON.stringify(f(A, B)));
גלעד ברקן
  • 23,602
  • 3
  • 25
  • 61
  • can you explain more of your code ? or can you provide me a solution in `c` or `c++` ? – unglinh279 Sep 27 '20 at 01:51
  • @user9920930 `diffs` would be something like a map type where the key is the difference (signed integer) and the value is a vector. We replace the value by a shorter vector if we can achieve it, so each value is always the shortest vector possible for the difference (the vector has the indexes of swaps). – גלעד ברקן Sep 27 '20 at 02:29
  • what does `diffs[d].concat()` means ? – unglinh279 Sep 27 '20 at 03:41
  • @user9920930 `diffs[d]` is the vector of indexes of swaps needed to achieve the difference, `d`. `concat` means adding more to it. In this case we are adding the index, `i` (plus 1 because your example has non-zero-based indexes in the result). – גלעד ברקן Sep 27 '20 at 04:00
  • @user9920930 so we're setting the value of the key `d1` in the map, `newDiffs`, to the vector we had for `d` plus the new index, `i`, since we decided this swap helped us achieve `d1`. – גלעד ברקן Sep 27 '20 at 04:03
  • what is `d` and `d1` ? are they arrays or integers ? and what does `Number(d)` means? – unglinh279 Sep 27 '20 at 10:49
  • @user9920930 `d` is one of the keys in the map, `diffs`, so it's one of the possible achievable differences up to this point. In JavaScript, map keys are strings so we apply `Number()` to convert it. `d1` is a (possibly) new difference we haven't seen yet, reached by applying the current `A[i]` and `B[i]` to the difference, `d`. – גלעד ברקן Sep 27 '20 at 10:58
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/222147/discussion-between-user9920930-and--). – unglinh279 Sep 27 '20 at 12:46
1

Here's a C++ implementation of mine based on Javascript answer of גלעד ברקן.


Short Explanation:

We maintain a mapping of all differences and their minimum swaps seen so far and try to extend all of the differences seen so far based on new values to get new mapping of such kind. We have 2 choices at each step when considering ith items in A and B, either consider the items as it is or swap the ith items.

Code:

#include <iostream>
#include <climits>
#include <unordered_map>
#include <vector>
using namespace std; // Pardon me for this sin


void update_keeping_existing_minimum(unordered_map<int, vector<int> >& mp, int key, vector<int>& value){
    if(mp.find(key) == mp.end() || mp[key].size() > value.size())mp[key] = value;
}

// Prints minimum swaps, indexes of swaps and minimum difference of sums
// Runtime is O(2^size_of_input) = 2^1 + 2^2 .. + 2^n = 2*2^n
// This is a bruteforce implementation.
// We try all possible cases, by expanding our array 1 index at time.
// For each previous difference,
// we use new index value and expand our possible difference outcomes.
// In worst case we may get 2 unique differences never seen before for every index.
void get_minimum_swaps(vector<int>& a, vector<int>& b){
    int n = a.size();

    unordered_map<int, vector<int> > prv_differences_mp;
    prv_differences_mp[0] = {}; // initial state

    for(int i = 0 ; i < n ; i++){
      unordered_map<int, vector<int> > new_differences_mp;
      
      for (auto& it: prv_differences_mp) {

          // possibility 1, we swap and expand previous difference
          int d = it.first;
          int d1 = d + b[i] - a[i];

          if(prv_differences_mp.find(d1) != prv_differences_mp.end() && prv_differences_mp[d1].size() < (prv_differences_mp[d].size() + 1)){
            update_keeping_existing_minimum(new_differences_mp, d1, prv_differences_mp[d1]);
          } else {
            // only place we are modifying the prv map, lets make a copy so that changes don't affect other calculations
            vector<int> temp = prv_differences_mp[d];
            temp.push_back(i+1);
            update_keeping_existing_minimum(new_differences_mp, d1, temp);
          }

          // possibility 2, we don't swap and expand previous difference
          int d2 = d + a[i] - b[i];
          if(prv_differences_mp.find(d2) != prv_differences_mp.end() && prv_differences_mp[d2].size() < prv_differences_mp[d].size()){
            update_keeping_existing_minimum(new_differences_mp, d2, prv_differences_mp[d2]);
          } else {
            update_keeping_existing_minimum(new_differences_mp, d2, prv_differences_mp[d]);
          }
      }
      
      cout<<i<<":index\n";
      for(auto& it: prv_differences_mp){
        cout<<it.first<<": [ ";
        for(auto& item: it.second)cout<<item<<" ";
        cout<<"] ; ";
      }
      cout<<"\n";
      prv_differences_mp = new_differences_mp;
    }

    int best = INT_MAX;
    vector<int> min_swap_ans;

    for(auto& it: prv_differences_mp){
      int _d = it.first >= 0 ? it.first: -it.first;
      if(_d < best){
        best = _d;
        min_swap_ans = it.second;
      }
    }
   
    cout<<"Number of swaps: "<<min_swap_ans.size()<<"\n";
    cout<<"Swapped indexes:\n";
    for(auto idx: min_swap_ans)cout<<idx<<" ";
    cout<<"\nDifference: "<<best<<"\n";

}

int main(){

  vector<int> A{ 1, 1, 4, 4, 0, 6 };
  vector<int> B{ 6, 3, 1, 1, 6, 1 };
  
  get_minimum_swaps(A, B);

  return 0;
}
รยקคгรђשค
  • 1,919
  • 1
  • 10
  • 18