Reduction Algorithm
A reduction algorithm transforms a complex problem into a simpler problem. By reducing to a solved problem, it enables reuse of existing solutions.
Some examples:
- Sorting by reduction to min/max problem
- Shortest paths via reduction to min weight edge problem
- NP-completeness reductions between problems
Java - Reduce sorting to min/max:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| int[] minSort(int[] arr) {
if (arr.length <= 1) return arr;
// Find min
int minIndex = findMinIndex(arr);
// Move to first position
swap(arr, 0, minIndex);
// Recursively sort rest
int[] sortedRest = minSort(Arrays.copyOfRange(arr, 1, arr.length));
// Combine
int[] result = new int[arr.length];
result[0] = arr[0];
System.arraycopy(sortedRest, 0, result, 1, sortedRest.length);
return result;
}
|
C++ - Shortest paths via minimum edge:
1
2
3
4
5
6
7
8
9
10
11
12
| int dijkstra(Graph graph, int src) {
// Min heap
priority_queue<Edge> pq;
// Initialize
while (!pq.empty()) {
Edge e = pq.top(); // Next min weight edge
// Process edge
}
}
|
Python - 3-SAT to Vertex Cover:
1
2
3
4
5
6
7
8
| from vertex_cover import minVertexCover
def reduce3SATtoVC(formula):
# Construct graph
# Vertices = clauses + literals
# Edges based on relationship
return minVertexCover(graph) # Returns min # clauses unsatisfied
|
Reduction allows reusing existing solutions by transforming problems into simpler forms.
Reduction is a technique used to solve one problem by transforming it into another problem, which is already known to be solvable. It’s like saying, “If we can solve problem B and we can reduce problem A to problem B, then we can solve problem A.” This is a cornerstone in computational theory, often employed to prove that specific problems are hard to solve.
Example Code in Java
Let’s consider the problem of finding the greatest common divisor (GCD) to reduce the problem of finding the least common multiple (LCM).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| public class ReductionExample {
public static int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
public static int lcm(int a, int b) {
return (a * b) / gcd(a, b);
}
public static void main(String[] args) {
int a = 12, b = 18;
System.out.println("LCM of " + a + " and " + b + " is: " + lcm(a, b));
}
}
|
Example Code in C++
The C++ version uses the same logic for GCD and LCM.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| #include <iostream>
using namespace std;
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
int lcm(int a, int b) {
return (a * b) / gcd(a, b);
}
int main() {
int a = 12, b = 18;
cout << "LCM of " << a << " and " << b << " is: " << lcm(a, b) << endl;
return 0;
}
|
Example Code in Python
In Python, we follow the same reduction logic to find the LCM using the GCD.
1
2
3
4
5
6
7
8
9
10
11
| def gcd(a, b):
if b == 0:
return a
return gcd(b, a % b)
def lcm(a, b):
return (a * b) // gcd(a, b)
a = 12
b = 18
print(f"LCM of {a} and {b} is: {lcm(a, b)}")
|
Here, we’ve reduced the problem of finding the LCM to the problem of finding the GCD. This is a classic example of algorithmic reduction.