Algorithmic approach to find Maximal Product - java

If 2 integers are given say a and b. Find b positive integers, such that their sum is equal to a and their product is maximal. We have to return the maximum product as an output.
Constraints are -
0<=b<=20
b<=a<=100
What sort of algorithm or approach has to be used to solve this question ?

Suppose we have two integers x,y such that x < y.
(x+1)*(y-1) = x*y + y - x - 1 >= x*y
This is saying that we can make the product bigger by increasing x and decreasing y.
Therefore the optimal answer will have all numbers within 1 unit of each other (or else we can get a better answer).
So our numbers are all equal to either x or x+1 (for some x yet to be determined). Suppose we have k of the bigger numbers, we know there must be b-k of the smaller ones. We can now compute x and k as follows:
x*(b-k)+k*(x+1) = a
b*x - k*x + k*x + k = a
b*x + k = a
therefore x = a // b and k = a % b.
The final product will be x**(b-k)*(x+1)**k.
(Note that there appears to be something odd with the question if sum is equal to a and b > a, because this will be impossible to achieve with positive integers.)

Related

Calculating the largest int less than the base 2 log of N

I have been reading Algorithms, 4th Edition, and it defines a question as follows:
Write a static method lg() that takes an int value N as an argument and returns the largest int not larger than the base-2 logarithm of N in Java. Do not use Math.
I discovered the following solution:
public static int lg(int N) {
int x = 0;
for (int n = N; n > 1; n/= 2) x++;
return x;
}
I am wondering why that solution works. Why does dividing by 2 continuously allow us to find the largest integer less than the base 2 logarithm of the argument? I do understand Java, just not how this particular algorithm works.
Thank you.
This has to do with properties of exponents and logarithms. The main observation you need is that
2lg n = n,
because logarithms are the inverses of exponentials. Rearranging that expression gives
1 = n / 2lg n.
In other words, the value of lg n is the number of times you have to divide n by two in order to drop it to 1. This, by the way, is a really great intuition to have when studying algorithms, since log terms show up all the time in contexts like these.
There are some other nuances here about how integer division works, but this is the basic idea behind why that code works.
Its follows trivially from the logarithmic identity log(a/b) = log(a) - log(b).
You are searching for the largest integer x so that:
x <= log2(n)
Using the identity above and taking in account that log2(2) = 1 we get:
x <= log2(n/2) + log2(2)
x <= log2(n/2) + 1
x <= log2(n/4) + 2
x <= log2(n/8) + 3
...
x <= log2(1) + k
x <= k (since log2(1) = 0)
So x is the number of times you divided n by 2 before reaching 1.
The answer is purely Mathmatics,
log₂(n) = ln(n)/ln(2) = x
By applying the rules of exponential:
ln(n) = ln(2)*(x)
n = 2^x
Therefore you have to divide by 2 until the value is smaller than 1 in order to get the closest int to it.
We are looking for the largest integer x such that x <= log_2(N) i.e. 2^x <= N
or equivalent 2^x <= N < 2^{x+1}
Let N_0=N
and for k > 0, N_k the quotient of the division of N_{k-1} by 2 and r_k in {0, 1} the remainder (N_{k-1} = 2.N_k + r_k)
We have:
2^{x-1} <= N_1 + (r_1 / 2) < 2^x
But 0 <= r_1 / 2 <= 1/2 and the others numbers are integers so that is equivalent to
2^{x-1} <= N_1 < 2^x
We have successively:
2^{x-1} <= N_1 < 2^x
2^{x-2} <= N_2 < 2^{x-1}
…
2^{x-x} <= N_x < 2^{x-x+1}
The last is also written 1 <= N_x < 2
But N_x is an integer so N_x = 1
Hence x is the number of division by 2 of N remaining greater or equal than 1.
Instead of starting from N_1, we can start from N_0 = N and stay greater than 1.

how to get value of three numbers knowing three information

I am trying to solve a problem that I need to get value of three unknowns(x,y,z) knowing some info. their summation is equal to 70, x^2 + y^2 = z^2 and x < y < z.
Answer should be x = 20, y = 21, z = 29
I tried to solve it as two equations in three unknowns but I failed. Any hints to get the solution ? I want to find an algorithm or equation to build a java code that solve this problem
I'll assume that x, y, and z must be positive integers, since removing the integers restriction allows infinitely many solutions. Here is an algorithm--I'll leave the code to you.
Your second equation x^2 + y^2 = z^2 means that x, y, and z form a Pythagorean triple. All solutions to that equation have the form
x = k(m^2 - n^2), y = 2kmn, z = k(m^2 + n^2)
(with possibly x and y swapped) where m, n, and k are positive integers, m > n, one of m and n is even and the other is odd, and (m, n) are relatively prime. You can drop those last two restrictions on m and n, which is to make the triples have unique representation.
Your third limitation x < y < z merely makes a unique triple from the three values. Importantly, your first restriction x + y + z = 70 means that your solution has "small" values.
So in your code, vary the three parameters k, m, and n. There are only finitely many values that allow the sum of x, y, and z to be less than or equal 70, which places limits on k, m, and n. Find the ones that equal make the sum of x, y, and z to be 70. You can cut the number of trials in half by not letting m and n be both even or both odd. You can also avoid explicitly varying k by varying only m and n and calculating what k should be, since each of x, y, z vary proportionally with k, and accept only integral k.
This is somewhat of a brute-force solution, but it is easy to program and will be faster than just trying all values of x, y, and z.
EDIT: I now see that x, y, and z may also be zero. That theoretically means that you need to test for x = 0, but that is clearly impossible here since then y^2 = z^2 which contradicts y < z. So no change is needed to my algorithm.
Expanding on #RoryDaulton's answer, taking x = k(m^2 - n^2), y = 2kmn and z = k(m^2 + n^2) and applying the sum constraint gives us
2*k*m*(m + n) = 70
Or
k * m * (m + n) = 35 = 7 * 5 = 35 * 1
The important thing to note is that the RHS of the above has only two unique factors; the LHS has three. Thus at least one factor of the LHS (k, m, m + n) must be 1.
Since m and n are unique positive integers, m + n will always be greater than 1. Thus,
k = 1 or m = 1
And the only possible values for the remaining LHS factors are 7 and 5 or 35 and 1.
This makes the problem much easier to brute force.
I have solved the question and I want to thank all people who helped me.
This is My code to solve the problem
int x,y,z;
long mul=0;
for(int n=1;n<=sum;n++){
for (int m=2;m<=sum;m++){
x= (int) ((Math.pow(m,2)) - (Math.pow(n,2)));
y= 2*m*n;
z= (int) ((Math.pow(m,2)) + (Math.pow(n,2)));
if(x+y+z == sum){
mul = x*z*y;
}
}}
return mul; }}

Selecting points such that sum of x coordinates = sum of y coordinates

I have an array of Points. I need to select a subset of points from it, such that the sum of x coordinates of the points = sum of y coordinates of the points.
If there are many such subsets, the one with largest sum of x coordinates is required.
The sum of x coordinates needs to be reported.
I have written a brute force recursive method, which tests all possibilities.
Point[] a = new Point[n];
// ...
private int rec(int i, int x, int y) {
if (i == n - 1) {
if (x + a[i].x == y + a[i].y) return x + a[i].x;
return (x == y) ? x : -1;
}
return Math.max(rec(i + 1, x, y), rec(i + 1, x + a[i].x, y + a[i].y));
}
The answer is rec(0, 0, 0).
My questions are:
1) Is there a dynamic programming solution for this?
2) If yes, could anyone please explain
I have a bit better (than brute force) algorithm.
Divided all coordinates into three sets: 1: {(x,y): x>y}, 2: {(x,y):x==y}, 3:{(x,y): x lower-than y}
Set 2 have to be always included in the solution.
for each (x,y) from 1 define net=x-y and for each (x,y) form 3 define net=y-x
check all possible values you can obtained from nets in 1 and nets in 3.
then basing on the greatest match it is easy to construct the solution.
Does it make sense?
For each point, set its value to x - y.
Now we need to find a set of points whose values sum to 0.
This is exactly the subset sum problem.
It is NP-complete (i.e. there is no known polynomial time algorithm for the generic case of the problem), but there exists a pseudo-polynomial time DP solution, which is given on Wikpedia, linked above. A brief summary:
We define a function Q(i,s) to be the value (true or false) of
there is a nonempty subset of x1, ..., xi which sums to s
Then we have the following recurrence:
Q(1,s) := (x1 == s)
Q(i,s) := Q(i − 1, s) or (xi == s) or Q(i − 1, s − xi) for A ≤ s ≤ B
Unless there are unstated constraints, the problem is NP-Hard by polynomial-time reduction of Subset-Sum, an NP-Complete problem.
One of the decision forms of Subset-Sum asks, given a set of integers, X, and an integer s, does any non-empty subset sum to s.
For each element of X, construct a Point whose x value is the element, and whose y value is zero. Construct one additional Point, whose x value is 0 and whose y value is s.
If the result of the equal-sum problem applied to that set of points is 0 or -1, then reject the subset-sum problem. If the result is s, then accept the subset-sum.
Assuming P != NP, or at least that we don't have any polynomial algorithm for any NP-Hard problem, there is no known polynomial-time algorithm for your problem.
just trying to code in java which would be helpful i felt:
for all i , diffOfCoordinates[i] = Xi - Yi
list will have the max points.
public void fun(int[] diffOfCoordinates, int indexA, int[] b, int indexB, int sum, List<Integer> list){
if(indexA == diffOfCoordinates.length){
if(sum==0){
if(list.size()<indexB){
list.clear();
for(int i=0;i<indexB;i++){
list.add(b[i]);
}
}
}
return;
}
b[indexB] = diffOfCoordinates[indexA];
fun(diffOfCoordinates, indexA+1, b, indexB+1, sum+diffOfCoordinates[indexA], list);
fun(diffOfCoordinates, indexA+1, b, indexB, sum, list);
}

Modulus in Java

I want to get the value of an unknown number in equation containing modulus % in Java
For example:
x % 26 = y if I have the value of y how can I get x
The problem is that there are either zero solutions (if Math.abs(y) >= 26) or an infinite1 number of values of x that satisfy that equation for a given y. The general answer is:
x = 26 * k + y
for any integer value of k. You can pick whatever k you want.2
1 In practice, the range will be limited by the range of integer values you are using. If x and y are int values, then you are limited by Integer.MAX_VALUE and Integer.MIN_VALUE. On the other hand, if they are BigInteger values, you don't have much in the way of range constraints.
2 Actually, the signs of x and y must be the same in Java, so you only have half of infinity to pick from. :-)
You can't get the value of x, that's how modulus works. You just know x = 26 * k + y where k is an integer.

Generate random numbers in increments

I need to generate n random numbers between a and b, but any two numbers cannot have a difference of less than c. All variables except n are floats (n is an int).
Solutions are preferred in java, but C/C++ is okay too.
Here is what code I have so far.:
static float getRandomNumberInRange(float min, float max) {
return (float) (min + (Math.random() * (max - min)));
}
static float[] randomNums(float a, float b, float c, int n) {
float minDistance = c;
float maxDistance = (b - a) - (n - 1) * c;
float[] randomNumArray = new float[n];
float random = getRandomNumberInRange(minDistance, maxDistance);
randomNumArray[0] = a + random;
for (int x = 1; x < n; x++) {
maxDistance = (b - a) - (randomNumArray[x - 1]) - (n - x - 1) * c;
random = getRandomNumberInRange(minDistance, maxDistance);
randomNumArray[x] = randomNumArray[x - 1] + random;
}
return randomNumArray;
}
If I run the function as such (10 times), I get the following output:
Input: randomNums(-1f, 1f, 0.1f, 10)
[-0.88, 0.85, 1.23, 1.3784, 1.49, 1.59, 1.69, 1.79, 1.89, 1.99]
[-0.73, -0.40, 0.17, 0.98, 1.47, 1.58, 1.69, 1.79, 1.89, 1.99]
[-0.49, 0.29, 0.54, 0.77, 1.09, 1.56, 1.69, 1.79, 1.89, 1.99]
I think a reasonable approach can be the following:
Total "space" is (b - a)
Remove the minimum required space (n-1)*c to obtain the remaining space
Shot (n-1) random numbers between 0 and 1 and scale them so that the sum is this just computed "optional space". Each of them will be a "slice" of space to be used.
First number is a
For each other number add c and the next "slice" to the previous number. Last number will be b.
If you don't want first and last to match a and b exactly then just create n+1 slices instead of n-1 and start with a+slice[0] instead of a.
The main idea is that once you remove the required spacing between the points (totalling (n-1)*c) the problem is just to find n-1 values so that the sum is the prescribed "optional space". To do this with a uniform distribution just shoot n-1 numbers, compute the sum and uniformly scale those numbers so that the sum is instead what you want by multiplying each of them by the constant factor k = wanted_sum / current_sum.
To obtain the final result you just use as spacing between a value and the previous one the sum of the mandatory part c and one of the randomly sampled variable parts.
An example in Python of the code needed for the computation is the following
space = b - a
slack = space - (n - 1)*c
slice = [random.random() for i in xrange(n-1)] # Pick (n-1) random numbers 0..1
k = slack / sum(slice) # Compute needed scaling
slice = [x*k for x in slice] # Scale to get slice sizes
result = [a]
for i in xrange(n-1):
result.append(result[-1] + slice[i] + c)
If you have random number X and you want another random number Y which is a minimum of A from X and a maximum of B from X, why not write that in your code?
float nextRandom(float base, float minDist, float maxDist) {
return base + minDist + (((float)Math.random()) * (maxDist - minDist));
}
by trying to keep the base out of the next number routine, you add a lot of complexity to your algorithm.
Though this does not exactly do what you need and does not incorporate the techinque being described in this thread, I believe that this code will prove to be useful as it will do what it seems like you want.
static float getRandomNumberInRange(float min, float max)
{
return (float) (min + (Math.random() * ((max - min))));
}
static float[] randomNums(float a, float b, float c, int n)
{
float averageDifference=(b-a)/n;
float[] randomNumArray = new float[n];
int random;
randomNumArray[0]=a+averageDifference/2;
for (int x = 1; x < n; x++)
randomNumArray[x]=randomNumArray[x-1]+averageDifference;
for (int x = 0; x < n; x++)
{
random = getRandomNumberInRange(-averageDifference/2, averageDifference/2);
randomNumArray[x]+=random;
}
return randomNumArray;
}
I need to generate n random numbers between a and b, but any two numbers cannot have a difference of less than c. All variables except n are floats (n is an int).
Solutions are preferred in java, but C/C++ is okay too.
First, what distribution? I'm going to assume a uniform distribution, but with that caveat that "any two numbers cannot have a difference of less than c". What you want is called "rejection sampling". There's a wikipedia article on the subject, plus a whole lot of other references on the 'net and in books (e.g. http://www.columbia.edu/~ks20/4703-Sigman/4703-07-Notes-ARM.pdf). Pseudocode, using some function random_uniform() that returns a random number drawn from U[0,1], and assuming a 1-based array (many languages use a 0-based array):
function generate_numbers (a, b, c, n, result)
result[1] = a + (b-a)*random_uniform()
for index from 2 to n
rejected = true
while (rejected)
result[index] = a + (b-a)*random_uniform()
rejected = abs (result[index] < result[index-1]) < c
end
end
Your solution was almost correct, here is the fix:
maxDistance = b - (randomNumArray[x - 1]) - (n - x - 1) * c;
I would do this by just generating n random numbers between a and b. Then I would sort them and get the first order differences, kicking out any numbers that generate a difference less than c, leaving me with m numbers. If m < n, I would just do it again, this time for n - m numbers, add those numbers to my original results, sort again, generate differences...and so on until I have n numbers.
Note, first order differences means x[1] - x[0], x[2] - x[1] and so on.
I don't have time to write this out in C but in R, it's pretty easy:
getRands<-function(n,a,b,c){
r<-c()
while(length(r) < n){
r<-sort(c(r,runif(n,a,b)))
r<-r[-(which(diff(r) <= c) + 1 )]
}
r
}
Note that if you are too aggresive with c relative to a and b, this kind of solution might take a long time to converge, or not converge at all if n * C > b -a
Also note, I don't mean for this R code to be a fully formed, production ready piece of code, just an illustration of the algorithm (for those who can follow R).
How about using a shifting range as you generate numbers to ensure that they don't appear too close?
static float[] randomNums(float min, float max, float separation, int n) {
float rangePerNumber = (max - min) / n;
// Check separation and range are consistent.
assert (rangePerNumber >= separation) : "You have a problem.";
float[] randomNumArray = new float[n];
// Set range for first random number
float lo = min;
float hi = lo + rangePerNumber;
for (int i = 0; i < n; ++i) {
float random = getRandomNumberInRange(lo, hi);
// Shift range for next random number.
lo = random + separation;
hi = lo + rangePerNumber;
randomNumArray[i] = random;
}
return randomNumArray;
}
I know you already accepted an answer, but I like this problem. I hope it's unique, I haven't gone through everyone's answers in detail just yet, and I need to run, so I'll just post this and hope it helps.
Think of it this way: Once you pick your first number, you have a chunk +/- c that you can no longer pick in.
So your first number is
range1=b-a
x=Random()*range1+a
At this point, x is somewhere between a and b (assuming Random() returns in 0 to 1). Now, we mark out the space we can no longer pick in
excludedMin=x-c
excludedMax=x+c
If x is close to either end, then it's easy, we just pick in the remaining space
if (excludedMin<=a)
{
range2=b-excludedMax
y=Random()*range2+excludedMax
}
Here, x is so close to a, that you won't get y between a and x, so you just pick between x+c and b. Likewise:
else if (excludedMax>=b)
{
range2=excludedMin-a
y=Random()*range2+a
}
Now if x is somewhere in the middle, we have to do a little magic
else
{
range2=b-a-2*c
y=Random()*range2+a
if (y>excludedMin) y+=2*c
}
What's going on here? Well, we know that the range y can lie in, is 2*c smaller than the whole space, so we pick a number somewhere in that smaller space. Now, if y is less than excludedMin, we know y "is to the left" of x-c, and we're all ok. However, if y>excluded min, we add 2*c (the total excluded space) to it, to ensure that it's greater than x+c, but it'll still be less than b because our range was reduced.
Now, it's easy to expand so n numbers, each time you just reduce the range by the excluded space among any of the other points. You continue until the excluded space equals the original range (b-a).
I know it's bad form to do a second answer, but I just thought of one...use a recursive search of the space:
Assume a global list of points: points
FillRandom(a,b,c)
{
range=b-a;
if (range>0)
{
x=Random()*range+a
points.Append(x)
FillRandom(a,x-c,c)
FillRandom(x+c,b,c)
}
}
I'll let you follow the recursion, but at the end, you'll have a list in points that fills the space with density 1/c

Categories