Skip to content

Commit 0dc55cf

Browse files
authored
Merge branch 'master' into sliding_window_new_algo
2 parents 8e9fe14 + f20f8d1 commit 0dc55cf

File tree

5 files changed

+168
-13
lines changed

5 files changed

+168
-13
lines changed

DIRECTORY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@
328328
* [StronglyConnectedComponentOptimized](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/graph/StronglyConnectedComponentOptimized.java)
329329
* greedyalgorithms
330330
* [ActivitySelection](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/ActivitySelection.java)
331+
* [BandwidthAllocation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/BandwidthAllocation.java)
331332
* [BinaryAddition](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/BinaryAddition.java)
332333
* [CoinChange](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/CoinChange.java)
333334
* [DigitSeparation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/DigitSeparation.java)
@@ -978,6 +979,7 @@
978979
* [StronglyConnectedComponentOptimizedTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/graph/StronglyConnectedComponentOptimizedTest.java)
979980
* greedyalgorithms
980981
* [ActivitySelectionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/ActivitySelectionTest.java)
982+
* [BandwidthAllocationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/BandwidthAllocationTest.java)
981983
* [BinaryAdditionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/BinaryAdditionTest.java)
982984
* [CoinChangeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/CoinChangeTest.java)
983985
* [DigitSeparationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/DigitSeparationTest.java)
Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,64 @@
11
package com.thealgorithms.conversions;
22

3+
/**
4+
* A utility class to perform affine transformations of the form:
5+
* y = slope * x + intercept.
6+
*
7+
* This class supports inversion and composition of affine transformations.
8+
* It is immutable, meaning each instance represents a fixed transformation.
9+
*/
310
public final class AffineConverter {
411
private final double slope;
512
private final double intercept;
13+
14+
/**
15+
* Constructs an AffineConverter with the given slope and intercept.
16+
*
17+
* @param inSlope The slope of the affine transformation.
18+
* @param inIntercept The intercept (constant term) of the affine transformation.
19+
* @throws IllegalArgumentException if either parameter is NaN.
20+
*/
621
public AffineConverter(final double inSlope, final double inIntercept) {
22+
if (Double.isNaN(inSlope) || Double.isNaN(inIntercept)) {
23+
throw new IllegalArgumentException("Slope and intercept must be valid numbers.");
24+
}
725
slope = inSlope;
826
intercept = inIntercept;
927
}
1028

29+
/**
30+
* Converts the given input value using the affine transformation:
31+
* result = slope * inValue + intercept.
32+
*
33+
* @param inValue The input value to convert.
34+
* @return The transformed value.
35+
*/
1136
public double convert(final double inValue) {
1237
return slope * inValue + intercept;
1338
}
1439

40+
/**
41+
* Returns a new AffineConverter representing the inverse of the current transformation.
42+
* The inverse of y = slope * x + intercept is x = (y - intercept) / slope.
43+
*
44+
* @return A new AffineConverter representing the inverse transformation.
45+
* @throws AssertionError if the slope is zero, as the inverse would be undefined.
46+
*/
1547
public AffineConverter invert() {
16-
assert slope != 0.0;
48+
assert slope != 0.0 : "Slope cannot be zero for inversion.";
1749
return new AffineConverter(1.0 / slope, -intercept / slope);
1850
}
1951

52+
/**
53+
* Composes this affine transformation with another, returning a new AffineConverter.
54+
* If this transformation is f(x) and the other is g(x), the result is f(g(x)).
55+
*
56+
* @param other Another AffineConverter to compose with.
57+
* @return A new AffineConverter representing the composition of the two transformations.
58+
*/
2059
public AffineConverter compose(final AffineConverter other) {
21-
return new AffineConverter(slope * other.slope, slope * other.intercept + intercept);
60+
double newSlope = slope * other.slope;
61+
double newIntercept = slope * other.intercept + intercept;
62+
return new AffineConverter(newSlope, newIntercept);
2263
}
2364
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.thealgorithms.greedyalgorithms;
2+
3+
import java.util.Arrays;
4+
5+
/**
6+
* Class to solve the Bandwidth Allocation Problem.
7+
* The goal is to maximize the value gained by allocating bandwidth to users.
8+
* Example:
9+
* Bandwidth = 10
10+
* Users = [3, 5, 7]
11+
* Values = [10, 20, 30]
12+
* The maximum value achievable is 40 by allocating 3 units to user 0 and 7 units to user 2.
13+
*
14+
* @author Hardvan
15+
*/
16+
public final class BandwidthAllocation {
17+
private BandwidthAllocation() {
18+
}
19+
20+
/**
21+
* Allocates bandwidth to maximize value.
22+
* Steps:
23+
* 1. Calculate the ratio of value/demand for each user.
24+
* 2. Sort the users in descending order of the ratio.
25+
* 3. Allocate bandwidth to users in order of the sorted list.
26+
* 4. If the bandwidth is not enough to allocate the full demand of a user, allocate a fraction of the demand.
27+
* 5. Return the maximum value achievable.
28+
*
29+
* @param bandwidth total available bandwidth to allocate
30+
* @param users array of user demands
31+
* @param values array of values associated with each user's demand
32+
* @return the maximum value achievable
33+
*/
34+
public static int maxValue(int bandwidth, int[] users, int[] values) {
35+
int n = users.length;
36+
double[][] ratio = new double[n][2]; // {index, ratio}
37+
38+
for (int i = 0; i < n; i++) {
39+
ratio[i][0] = i;
40+
ratio[i][1] = (double) values[i] / users[i];
41+
}
42+
43+
Arrays.sort(ratio, (a, b) -> Double.compare(b[1], a[1]));
44+
45+
int maxValue = 0;
46+
for (int i = 0; i < n; i++) {
47+
int index = (int) ratio[i][0];
48+
if (bandwidth >= users[index]) {
49+
maxValue += values[index];
50+
bandwidth -= users[index];
51+
} else {
52+
maxValue += (int) (ratio[i][1] * bandwidth);
53+
break;
54+
}
55+
}
56+
return maxValue;
57+
}
58+
}

src/test/java/com/thealgorithms/conversions/AffineConverterTest.java

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,39 @@ void setUp() {
1616
}
1717

1818
@Test
19-
void testConstructor() {
19+
void testConstructorWithValidValues() {
2020
assertEquals(3.0, converter.convert(0.0), "Expected value when input is 0.0");
2121
assertEquals(5.0, converter.convert(1.0), "Expected value when input is 1.0");
22-
assertEquals(7.0, converter.convert(2.0), "Expected value when input is 2.0");
2322
}
2423

2524
@Test
26-
void testConvert() {
27-
assertEquals(3.0, converter.convert(0.0), "Conversion at 0.0 should equal the intercept");
28-
assertEquals(7.0, converter.convert(2.0), "2.0 should convert to 7.0");
29-
assertEquals(11.0, converter.convert(4.0), "4.0 should convert to 11.0");
25+
void testConstructorWithInvalidValues() {
26+
assertThrows(IllegalArgumentException.class, () -> new AffineConverter(Double.NaN, 3.0), "Constructor should throw IllegalArgumentException for NaN slope");
27+
}
28+
29+
@Test
30+
void testConvertWithNegativeValues() {
31+
assertEquals(-1.0, converter.convert(-2.0), "Negative input should convert correctly");
32+
assertEquals(-3.0, new AffineConverter(-1.0, -1.0).convert(2.0), "Slope and intercept can be negative");
33+
}
34+
35+
@Test
36+
void testConvertWithFloatingPointPrecision() {
37+
double result = new AffineConverter(1.3333, 0.6667).convert(3.0);
38+
assertEquals(4.6666, result, 1e-4, "Conversion should maintain floating-point precision");
3039
}
3140

3241
@Test
3342
void testInvert() {
3443
AffineConverter inverted = converter.invert();
35-
assertEquals(0.0, inverted.convert(3.0), "Inverted converter should return 0.0 for input 3.0");
36-
assertEquals(1.0, inverted.convert(5.0), "Inverted converter should return 1.0 for input 5.0");
37-
assertEquals(2.0, inverted.convert(7.0), "Inverted converter should return 2.0 for input 7.0");
44+
assertEquals(0.0, inverted.convert(3.0), "Inverted should return 0.0 for input 3.0");
45+
assertEquals(1.0, inverted.convert(5.0), "Inverted should return 1.0 for input 5.0");
3846
}
3947

4048
@Test
4149
void testInvertWithZeroSlope() {
4250
AffineConverter zeroSlopeConverter = new AffineConverter(0.0, 3.0);
43-
assertThrows(AssertionError.class, zeroSlopeConverter::invert, "Invert should throw assertion error when slope is zero");
51+
assertThrows(AssertionError.class, zeroSlopeConverter::invert, "Invert should throw AssertionError when slope is zero");
4452
}
4553

4654
@Test
@@ -50,6 +58,30 @@ void testCompose() {
5058

5159
assertEquals(7.0, composed.convert(0.0), "Expected composed conversion at 0.0");
5260
assertEquals(9.0, composed.convert(1.0), "Expected composed conversion at 1.0");
53-
assertEquals(11.0, composed.convert(2.0), "Expected composed conversion at 2.0");
61+
}
62+
63+
@Test
64+
void testMultipleCompositions() {
65+
AffineConverter c1 = new AffineConverter(2.0, 1.0);
66+
AffineConverter c2 = new AffineConverter(3.0, -2.0);
67+
AffineConverter c3 = c1.compose(c2); // (2x + 1) ∘ (3x - 2) => 6x - 1
68+
69+
assertEquals(-3.0, c3.convert(0.0), "Composed transformation should return -3.0 at 0.0");
70+
assertEquals(3.0, c3.convert(1.0), "Composed transformation should return 3.0 at 1.0");
71+
}
72+
73+
@Test
74+
void testIdentityComposition() {
75+
AffineConverter identity = new AffineConverter(1.0, 0.0);
76+
AffineConverter composed = converter.compose(identity);
77+
78+
assertEquals(3.0, composed.convert(0.0), "Identity composition should not change the transformation");
79+
assertEquals(7.0, composed.convert(2.0), "Identity composition should behave like the original");
80+
}
81+
82+
@Test
83+
void testLargeInputs() {
84+
double largeValue = 1e6;
85+
assertEquals(2.0 * largeValue + 3.0, converter.convert(largeValue), "Should handle large input values without overflow");
5486
}
5587
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.thealgorithms.greedyalgorithms;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.util.stream.Stream;
6+
import org.junit.jupiter.params.ParameterizedTest;
7+
import org.junit.jupiter.params.provider.Arguments;
8+
import org.junit.jupiter.params.provider.MethodSource;
9+
10+
public class BandwidthAllocationTest {
11+
12+
@ParameterizedTest
13+
@MethodSource("bandwidthProvider")
14+
public void testMaxValue(int capacity, int[] bandwidths, int[] values, int expected) {
15+
assertEquals(expected, BandwidthAllocation.maxValue(capacity, bandwidths, values));
16+
}
17+
18+
private static Stream<Arguments> bandwidthProvider() {
19+
return Stream.of(Arguments.of(50, new int[] {20, 10, 30}, new int[] {40, 20, 30}, 80), Arguments.of(0, new int[] {5, 10}, new int[] {10, 20}, 0), Arguments.of(5, new int[] {5, 10}, new int[] {10, 20}, 10), Arguments.of(15, new int[] {10, 20}, new int[] {10, 25}, 18),
20+
Arguments.of(25, new int[] {10, 15, 20}, new int[] {10, 30, 50}, 60));
21+
}
22+
}

0 commit comments

Comments
 (0)