Divide-and-Conquer
The divide-and-conquer paradigm involves three steps at each level of the recursion:
- Divide the problem into a number of subproblems that are smaller instances of the same problem.
- Conquer the subproblems by solving them recursively. If the subproblem sizes are small enough, however, just solve the subproblems in a straightforward manner.
- Combine the solutions to the subproblems into the solution for the original problem.
When can we use Divide and Conquer?
- Original problem is easily decomposable into subproblems (we don not want to see “overlap” in the subproblems).
- Combining solutions is not too costly.
- Subproblems are not overly unbalanced.
Example - Counting inversions
Collaborative filtering:
- matches users preferences (movies, music, …)
- determine users with similar tastes
- recommends n ew things to users based on preferences of similar users
Goal: given an unsorted array , find the number of inversions in it.
Def
is an inversion if and
Example: with
A=[1,5,2,6,3,8,7,4]
, we get
Remark: we show the indices where inversions occur
Remark: easy algorithm (two nested loops) in
random
Idea: solve the problem twice in size (we assume is a power of 2). Then the optimal subarray (if not empty)
- is completely in the left half
- or is completely in the right half
- or contains both and (cases mutually exclusive)
PQ1
Tower Domination: There are towers defined by their integer coordinates and , . We say that a tower dominates a tower if and only if
That is, the coordinates of tower are either both greater, or both smaller, than the coordinates of tower . Define the dominance factor of tower as the total number of towers dominated by it. Your task is to design a divide-and-conquer algorithm to compute the dominance factor of each tower.
My solution:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Tower {
int index;
pair<int, int> tower;
};
int divide_and_conquer_dominance(vector<Tower>& towers, vector<int>& dominance_factor, size_t start, size_t end) {
if (start >= end) {
return 0;
}
size_t mid = start + (end - start) / 2;
divide_and_conquer_dominance(towers, dominance_factor, start, mid);
divide_and_conquer_dominance(towers, dominance_factor, mid + 1, end);
// merge the dominance factor
//copy towers to a new array temp
vector<Tower> temp(towers.begin() + start, towers.begin() + end + 1);
//perform merge sort
size_t i = 0, j = mid - start + 1;
size_t k = start;
while (i < mid - start + 1 && j < end - start + 1) {
if (temp[i].tower.second < temp[j].tower.second) {
dominance_factor[temp[i].index] += end -start - j + 1;
towers[k++] = temp[i++];
} else {
dominance_factor[temp[j].index] += i;
towers[k++] = temp[j++];
}
}
while (i < mid - start + 1) {
towers[k++] = temp[i++];
}
while (j < end - start + 1) {
dominance_factor[temp[j].index] += i;
towers[k++] = temp[j++];
}
return 0;
}
int main() {
int n;
cin >> n;
vector<pair<int, int>> coordOfTowers(n);
vector<int> dominance_factor(n, 0);
vector<Tower> myTowers(n);
for (int i = 0; i < n; ++i) {
cin >> myTowers[i].tower.first >> myTowers[i].tower.second;
myTowers[i].index = i;
}
// call libary function to sort the towers based on towers.first (x coordinate)
sort(myTowers.begin(), myTowers.end(), [](Tower a, Tower b) {
return a.tower.first < b.tower.first;
});
divide_and_conquer_dominance(myTowers, dominance_factor, 0, myTowers.size() - 1);
// Output the dominance factor
for (size_t i = 0; i < dominance_factor.size(); ++i) {
cout << dominance_factor[i] << " ";
}
cout << endl;
return 0;
}