Find a matrix which satisfies certain constraints - java

Another description of the problem: Compute a matrix which satisfies certain constraints
Given a function whose only argument is a 4x4 matrix (int[4][4] matrix), determine the maximal possible output (return value) of that function.
The 4x4 matrix must satisfy the following constraints:
All entries are integers between -10 and 10 (inclusively).
It must be symmetrix, entry(x,y) = entry(y,x).
Diagonal entries must be positive, entry(x,x) > 0.
The sum of all 16 entries must be 0.
The function must only sum up values of the matrix, nothing fancy.
My question:
Given such a function which sums up certain values of a matrix (matrix satisfies above constraints), how do I find the maximal possible output/return value of that function?
For example:
/* The function sums up certain values of the matrix,
a value can be summed up multiple or 0 times. */
// for this example I arbitrarily chose values at (0,0), (1,2), (0,3), (1,1).
int exampleFunction(int[][] matrix) {
int a = matrix[0][0];
int b = matrix[1][2];
int c = matrix[0][3];
int d = matrix[1][1];
return a+b+c+d;
}
/* The result (max output of the above function) is 40,
it can be achieved by the following matrix: */
0. 1. 2. 3.
0. 10 -10 -10 10
1. -10 10 10 -10
2. -10 10 1 -1
3. 10 -10 -1 1
// Another example:
// for this example I arbitrarily chose values at (0,3), (0,1), (0,1), (0,4), ...
int exampleFunction2(int[][] matrix) {
int a = matrix[0][3] + matrix[0][1] + matrix[0][1];
int b = matrix[0][3] + matrix[0][3] + matrix[0][2];
int c = matrix[1][2] + matrix[2][1] + matrix[3][1];
int d = matrix[1][3] + matrix[2][3] + matrix[3][2];
return a+b+c+d;
}
/* The result (max output of the above function) is -4, it can be achieved by
the following matrix: */
0. 1. 2. 3.
0. 1 10 10 -10
1. 10 1 -1 -10
2. 10 -1 1 -1
3. -10 -10 -1 1
I don't know where to start. Currently I'm trying to estimate the number of 4x4 matrices which satisfy the constraints, if the number is small enough the problem could be solved by brute force.
Is there a more general approach?
Can the solution to this problem be generalized such that it can be easily adapted to arbitrary functions on the given matrix and arbitrary constraints for the matrix?

You can try to solve this using linear programming techniques.
The idea is to express the problem as some inequalities, some equalities, and a linear objective function and then call a library to optimize the result.
Python code:
import scipy.optimize as opt
c = [0]*16
def use(y,x):
c[y*4+x] -= 1
if 0:
use(0,0)
use(1,2)
use(0,3)
use(1,1)
else:
use(0,3)
use(0,1)
use(0,1)
use(0,3)
use(0,3)
use(0,2)
use(1,2)
use(2,1)
use(3,1)
use(1,3)
use(2,3)
use(3,2)
bounds=[ [-10,10] for i in range(4*4) ]
for i in range(4):
bounds[i*4+i] = [1,10]
A_eq = [[1] * 16]
b_eq = [0]
for x in range(4):
for y in range(x+1,4):
D = [0]*16
D[x*4+y] = 1
D[y*4+x] = -1
A_eq.append(D)
b_eq.append(0)
r = opt.linprog(c,A_eq=A_eq,b_eq=b_eq,bounds=bounds)
for y in range(4):
print r.x[4*y:4*y+4]
print -r.fun
This prints:
[ 1. 10. -10. 10.]
[ 10. 1. 8. -10.]
[-10. 8. 1. -10.]
[ 10. -10. -10. 1.]
16.0
saying that the best value for your second case is 16, with the given matrix.
Strictly speaking you are wanting integer solutions. Linear programming solves this type of problem when the inputs can be any real values, while integer programming solves this type when the inputs must be integers.
In your case you may well find that the linear programming method already provides integer solutions (it does for the two given examples). When this happens, it is certain that this is the optimal answer.
However, if the variables are not integral you may need to find an integer programming library instead.

Sort the elements in the matrix in descending order and store in an array.Iterate through the elements in the array one by one
and add it to a variable.Stop iterating at the point when adding an element to variable decrease its value.The value stored in the variable gives maximum value.
maxfunction(matrix[][])
{
array(n)=sortDescending(matrix[][]);
max=n[0];
i=1;
for i to n do
temp=max;
max=max+n[i];
if(max<temp)
break;
return max;
}

You need to first consider what matrices will satisfy the rules. The 4 numbers on the diagonal must be positive, with the minimal sum of the diagonal being 4 (four 1 values), and the maximum being 40 (four 10 values).
The total sum of all 16 items is 0 - or to put it another way, sum(diagnoal)+sum(rest-of-matrix)=0.
Since you know that sum(diagonal) is positive, that means that sum(rest-of-matrix) must be negative and equal - basically sum(diagonal)*(-1).
We also know that the rest of the matrix is symmetrical - so you're guaranteed the sum(rest-of-matrix) is an even number. That means that the diagonal must also be an even number, and the sum of the top half of the matrix is exactly half the diagonal*(-1).
For any given function, you take a handful of cells and sum them. Now you can consider the functions as fitting into categories. For functions that take all 4 cells from the diagonal only, the maximum will be 40. If the function takes all 12 cells which are not the diagonal, the maximum is -4 (negative minimal diagonal).
Other categories of functions that have an easy answer:
1) one from the diagonal and an entire half of the matrix above/below the diagonal - the max is 3. The diagonal cell will be 10, the rest will be 1, 1, 2 (minimal to get to an even number) and the half-matrix will sum at -7.
2) two cells of the diagonal and half a matrix - the max is 9. the two diagonal cells are maximised to two tens, the remaining cells are 1,1 - and so the half matrix sums at -11.
3) three cells from the diagonal and half a matrix - the max is 14.
4) the entire diagonal and half the matrix - the max is 20.
You can continue with the categories of selecting functions (using some from the diagonal and some from the rest), and easily calculating the maximum for each category of selecting function. I believe they can all be mapped.
Then the only step is to put your new selecting function in the correct category and you know the maximum.

Related

find the maximum possible ones

I have a string of 0's and 1's
Now I want to change 0 to 1 only if adjacent elements for that 0 are not 1'string. Find the maximum ones possible after doing this operation.
Example:
110011000001 is the input string
Option 1:
I can change position 8 and position 10 from 0 to 1 to make the string: 110011010101, here there are 7 ones
Option 2:
Another way is to change position 9 from 0 to 1, to make the string: 110011001001, here there are 6 ones.
So the maximum between 6 and 7 is 7. So the result is 7.
Here is my code, I am able to find only one possible way here:
int process(String s) {
char[] ch = s.toCharArray();
int n = ch.length;
for(int i=1; i<n-1; i++) {
char e = ch[i];
if(e == '0' && ch[i-1] != '1' && ch[i+1] != '1') {
ch[i] = '1';
}
}
int count = 0;
for(char c : ch) {
if(c == '1') count++;
}
return count;
}
How to get the maximum possible ones here.
Notice that if the 0's are surrounded by 1's, you only need 2n + 1
adjacent 0's in order to add n 1's. In order to add one 1, you
need at least three 0's: 2*1+1=3. In order to add two 1's, you
need at least five 0's: 2*2+1=5. Since the number of 0's can be
described as, Z >= 2n + 1, we can instead solve for n. We get n <= (Z - 1) / 2. Thus, when surrounded by 1's, each group of 0's can
fit n=floor((Z-1)/2); we floor the value since we can't add half of a 1.
For groups of 0's only bounded by a 1 on a single side, we notice
that we need at least 2n 0's in order to add n 1's. Again, we
rearrange the equation Z >= 2n in order to get n <= Z / 2. Thus,
for groups bounded by a single 1, n=floor(Z/2).
For our last case, with a string of all 0's, we see that Z >= 2n - 1. So, n <= (Z + 1) / 2, or for our purposes floor((Z+1)/2).
Least common will be category 3. This will only happen if there are no 1's. If this is the case, you cannot have anything from category 1 or 2 -- so check this category first.
Second most common will be category 2. This happens when the beginning OR end of the string is a 0, but there are 1's elsewhere. Check this category second because you can fit more 1's with it than with the formula for the first case. Depending on your solution, you may have to keep track of the places you've already checked before moving on to using case 1 by using a substring of the original.
Most cases will land in category 1, since (in a random combination of 1's and 0's) most groups of 0's will be surrounded by 1's.
Your answer only checks the first case. Using these three cases together will give you the number of 1's that you can add to the string. Add this to the number of 1's you had originally and you'll have your answer.
Edited for clarity.
Count all existing ones as they are going to be a part of the answer.
To convert 0 to 1, count all zeroes between two ones.
If string is 100001, you have total 4 zeroes in between. Here let us leave boundary zeroes as we can't change them as they are adjacent to 1. So, now we are left with 2 zeroes in the middle out of which we can place only in 1 of them.
So count is just ceil(all valid zeroes / 2).
If you have a string like 00001, here you can place 2 ones excluding that boundary 0 adjacent to 1. So, count is ceil(3/2) which is 2. Your string would look like 10101.
Final answer is just step 1 + step 2.

Multiply numbers represented as Linked List

I've been trying to solve this problem for a while, now, but none of my approaches have worked so far.
You're given two linked lists that represents big numbers, where the head of the lists represent the least significant digit.
Return a new list which stores the result of the multiplication of the two lists.
I've tried an algorithm that worked for the first list being a single number, but not more than that.
Initialize a new list.
Initialize a carry.
While node 1 is not null:
While node 2 is not null:
If node 3's next is not null, add it's value to the carry;
Set node 3's next as node 1 * node 2's value + carry.
Set node 2 as it's next, set node 3 as it's next.
End while set at section 4
Set node 1 as node 1's next.
End while set at section 3.
Return list set at section 1.
This obviously has problems. I've also tried to set a "powCounter" for each iteration of the first loop, and multiply the value by 10 to the power of powCounter.
But this didn't work either.
I'd really appreciate any help!
Do it like you would on paper.
Presumably, before tasking you to write multiply(a, b), they would have already had you write add(a, b), right? So use that.
You said you already wrote logic for multiply with a single digit, so let calls that multiplySingle(a, digit).
You need one more helper method, e.g. shiftLeft(a, n), which adds n 0's to the end of the number, i.e. to the beginning of the list. E.g. shiftLeft([4,3,2,1], 2) should return [0,0,4,3,2,1], meaning 1234 * 10² = 123400.
So, on paper you would multiply 123 with 456 like this:
123 * 456
45600 = 1 * 456 * 100 = shiftLeft(multiplySingle([6,5,4], 1), 2)
9120 = 2 * 456 * 10 = shiftLeft(multiplySingle([6,5,4], 2), 1)
1368 = 3 * 456 * 1 = shiftLeft(multiplySingle([6,5,4], 3), 0)
=====
56088 = 45600 + 9120 + 1368 = add(add([0,0,6,5,4], [0,2,1,9]), [8,6,3,1])
Good luck writing the code for that.
FYI: The idea for a shiftLeft() method is based on similar methods in the built-in BigInteger and BigDecimal classes.
BigInteger shiftLeft(int n)
Returns a BigInteger whose value is (this << n). The shift distance, n, may be negative, in which case this method performs a right shift. (Computes floor(this * 2ⁿ).)
BigDecimal movePointRight(int n)
Returns a BigDecimal which is equivalent to this one with the decimal point moved n places to the right. If n is non-negative, the call merely subtracts n from the scale. If n is negative, the call is equivalent to movePointLeft(-n). The BigDecimal returned by this call has value (this × 10ⁿ) and scale max(this.scale()-n, 0).

Iterate all possible results of add subtract 6 float variables

Stuck here and hope this is easy for someone with the right experience.
I'm trying to find a way to calculate all combinations of 6 float variables. Add, subtract, and zero. I can do this with a massive switch/case statement but expect there must be some more intelligent approach to this problem.
A set of nested for loops? Recursion? Put the 6 vars into an array and have a second method to add,subtract,zero?
I prefer to avoid using any matrix or collection libraries and just do in pure Java. Example of what I mean:
public int mixVars6(int selector, float A, float B, float C, float D, float E, float F) {
switch (selector) {
case 0:
return Math.round(A - B - C - D - E - F);
case 1:
return Math.round(A - B - C - D - E + F);
case 2:
return Math.round(A - B - C - D - E + 0); // exclude F
// continues so that each variation of + and - is covered
case xx: // more complex example:
return Math.round(A + B + C - D - E + F);
}
}
EDIT: In response to comments: It is not a school project. I'm trying to find out a combination of leading, top, bottom, ascent, decent variations on a TrueType font rendering problem I'm having. Some of the values are negative and position I can't find the desired combination using proper methods. I'm trying to find a way to iterate all the variations of these variables. The selector is tied to a hardware button and I'm visually reviewing the layout changes as I increment it +1.
EDIT: I think there is probably a way to do this with 3 nested for loops that modulus the selector? The operator can be expressed this way:
// Addition, subtraction, and zero can be achieved by multiplication
float[] operators = { 1f, -1f, 0f };
Thank you
You need a recursive function, whose header looks like
public static void combineFloats(float[] floats, float currentSum, int idx)
Where the float array contains all of your numbers, and in the initial call, currentSum is 0, and idx = 0, with idx getting bigger by 1 every time you descend recursively
There are 5 positions where +/- can be added(let's not consider the case of 0's at the moment), there will be 32 combinations(2^5).
Now for each of 32 combinations, we can start applying that "0" condition, again with the similar procedure, since there are 6 digits(A,B,C,D,E,F), the combinations would be 64(2^6).
Now the biggest problem is: How to iterate through those permutations:
Simple, binary counting would help.
Example: Suppose,
00000 represents all symbols are plus.
00001 would represent all symbols are plus but last one is minus
and so on
Similarly, 0's can mean that the digit at that position has to be taken and 1 would mean that it shouldn't be taken.
you will just need a for loop which would do binary counting upto 5 digits, and inside it another for loop which would do binary counting upto 6 digits, and handle the rest of your code(arrays or whatever) accordingly.
Here is the idea (I will leave the implementation for you):
For 6 variables there will be 5 operators. If we represent "-" as 0 and "+" as 1 then all possible combinations of operators will be represented by numbers from 00000 to 11111 which is from 0 to 31.
0 -> 00000 -> A-B-C-D-E-F
1 -> 00001 -> A-B-C-D-E+F
.....
31 -> 11111 -> A+B+C+D+E+F
How about 0? You just need to go through all 31 combinations above and replace each var at each position with 0.
So the algorithm is:
For each number from 0 to 31
Convert the number to binary and append to make enough 5 digits
Extract 5 digits from generated binary
For each 0 replace with -, for each 1 replaces with + and form the expression
For each position replace the variables with 0

Randomly break up array into chunks of at least 3 with even distribution

I have an array of size n, and would like to break it up into m chunks of size at least 3. For example,
given the array
[1,2,3,4,5,6,7,8,9,10]
and m=3, we could break the it up into
a=[1,2,3,4][5,6,7][8,9,10]
b=[1,2,3][4,5,6,7][8,9,10]
c=[1,2,3][4,5,6][7,8,9,10]
We could think of these solutions as being represented by the pairs (4,3,3) (3,4,3) and (3,3,4).
I would like a function that given an array, n, and m, returns a random solution AND returns these solutions with an even distribution (so that you are no more likely to get one particular solution than any other). (This function needs to work for n=50, so for performance reasons we cannot do this by calculating all possible solutions.)
So, in the case above, this method would return [4,3,3] a third of the time, [3,4,3] a third of the time, and [3,3,4] a third of the time.
Just a thought:
Let's say m=3, n=20. What we can do is to do this:
Choose a number between m and n - 2*m (between 3 and 14)
Let's say we random 6. This will be the first set and let's call it p1
Choose a number between our new subset of [m, [n - m - p1]] i.e. the subset of [3, 20 - 6 - 3] or [3, 11]
Let's say we roll 10. This is p2
Size of the remainder (or p3) will be 20 -p1 -p2 = 4
Final set will be [6, 10, 4]
Would this work? It wouldn't need any sort of iteration over the original list either. Your only iteration will be over m and not dependent on n.
I can try to make this more generic for variable m (step 1will need to change slightly and steps 3 and 5 will be in a loop) but I'm sure you can work it out if this solution is acceptable to you.
Example rewrite for step 1 would be:
Choose a number between m and n - [m - 1] * m
Would this work?
def randomCollate(item, chunk) {
def collated = item.collate( chunk )
def remainder = collated.reverse().takeWhile { it.size() != chunk }.flatten()
def randomIdx = new Random().nextInt( ( collated - remainder ).size() )
collated[randomIdx] += remainder
collated - [ remainder ]
}
randomCollate( 1..50, 3 )
Another idea I just had
Calculate how many array you are going to have with size m and how many with size m+1 (or a different sice). Let's call these values x and y.
Calculate the amount of possible permutations [3,3,4],[3,4,3],[4,3,3] -> 3 permutations (x+y)Py (binomial coefficient)
Chose a random permutation from 0 - possible permutations. Lets call this Z.
From now on I don't exactly know how this could be done, but I would try this:
Imagine you got a binary number with n digits and y of those are zeros. Get the Zst possible binary number with exactly y zeros and x ones.
Example binary: 100101101
Your result would be [x,y,y,x,y,x,x,y,x]
I hope you understand what I mean.
for each step allow a random range of n-m*min (min is 3 in your example); then pick a number from that range, add min, as r. if m is 2 return a list of r and n-r. otherwise return r and the result of the recursive call with n-r, m-1. shuffle this and you have the random sizes of the chunks.
rnd = new Random()
// build the chunk size list to randomly split `n` elements in `m` parts,
// where each part is at least of size `min`
// needs a shuffle afterwards
def s(n,m,min=3) {
def l = n-m*min // the range where we can pick a random offset
def r = min + (l?rnd.nextInt(l):0) // result for this step with optional random part
m==2 ? [r,n-r] : [r]+s(n-r,m-1) // only two remaining? pick result and remainder, or recurse
}
def tests = [[9,3,3],[10,3,3],[27,9,3],[4,2,2]]
1000.times{
tests.each{ n,m,min ->
def r = s(n,m,min)
assert r.sum()==n
assert r.size()==m
assert r.every{ it>= min }
}
}
def items = (0..9).collect() // test list
def slices = s(items.size(),3) // get the chunk sizes
Collections.shuffle(slices) // shuffle the result
// create ranges and use them to get the slices; should be another one or two methods
println slices.inject([sum:0,result:[]]) { r,s -> r.result<<items[((r.sum)..(r.sum+s-1))]; r.sum+=s; r }.result
//=> e.g. [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9]]

truncated binary logarithm

I have a question about this problem, and any help would be great!
Write a program that takes one integer N as an
argument and prints out its truncated binary logarithm [log2 N]. Hint: [log2 N] = l is the largest integer ` such that
2^l <= N.
I got this much down:
int N = Integer.parseInt(args[0]);
double l = Math.log(N) / Math.log(2);
double a = Math.pow(2, l);
But I can't figure out how to truncate l while keeping 2^l <= N
Thanks
This is what i have now:
int N = Integer.parseInt(args[0]);
int i = 0; // loop control counter
int v = 1; // current power of two
while (Math.pow(2 , i) <= N) {
i = i + 1;
v = 2 * v;
}
System.out.println(Integer.highestOneBit(N));
This prints out the integer that is equal to 2^i which would be less than N. My test still comes out false and i think that is because the question is asking to print the i that is the largest rather than the N. So when i do
Integer.highestOneBit(i)
the correct i does not print out. For example if i do: N = 38 then the highest i should be 5, but instead it prints out 4.
Then i tried this:
int N = Integer.parseInt(args[0]);
int i; // loop control counter
for (i= 0; Math.pow(2 , i) == N; i++) {
}
System.out.println(Integer.highestOneBit(i));
Where if i make N = 2 i should print out to be 1, but instead it is printing out 0.
I've tried a bunch of things on top of that, but cant get what i am doing wrong. Help would be greatly appreciated. Thanks
I believe the answer you're looking for here is based on the underlying notion of how a number is actually stored in a computer, and how that can be used to your advantage in a problem such as this.
Numbers in a computer are stored in binary - a series of ones and zeros where each column represents a power of 2:
(Above image from http://www.mathincomputers.com/binary.html - see for more info on binary)
The zeroth power of 2 is over on the right. So, 01001, for example, represents the decimal value 2^0 + 2^3; 9.
This storage format, interestingly, gives us some additional information about the number. We can see that 2^3 is the highest power of 2 that 9 is made up of. Let's imagine it's the only power of two it contains, by chopping off all the other 1's except the highest. This is a truncation, and results in this:
01000
You'll now notice this value represents 8, or 2^3. Taking it down to basics, lets now look at what log base 2 really represents. It's the number that you raise 2 to the power of to get the thing your finding the log of. log2(8) is 3. Can you see the pattern emerging here?
The position of the highest bit can be used as an approximation to it's log base 2 value.
2^3 is the 3rd bit over in our example, so a truncated approximation to log base 2(9) is 3.
So the truncated binary logarithm of 9 is 3. 2^3 is less than 9; This is where the less than comes from, and the algorithm to find it's value simply involves finding the position of the highest bit that makes up the number.
Some more examples:
12 = 1100. Position of the highest bit = 3 (starting from zero on the right). Therefore the truncated binary logarithm of 12 = 3. 2^3 is <= 12.
38 = 100110. Position of the highest bit = 5. Therefore the truncated binary logarithm of 38 = 5. 2^5 is <= 38.
This level of pushing bits around is known as bitwise operations in Java.
Integer.highestOneBit(n) returns essentially the truncated value. So if n was 9 (1001), highestOneBit(9) returns 8 (1000), which may be of use.
A simple way of finding the position of that highest bit of a number involves doing a bitshift until the value is zero. Something a little like this:
// Input number - 1001:
int n=9;
int position=0;
// Cache the input number - the loop destroys it.
int originalN=n;
while( n!=0 ){
position++; // Also position = position + 1;
n = n>>1; // Shift the bits over one spot (Overwriting n).
// 1001 becomes 0100, then 0010, then 0001, then 0000 on each iteration.
// Hopefully you can then see that n is zero when we've
// pushed all the bits off.
}
// Position is now the point at which n became zero.
// In your case, this is also the value of your truncated binary log.
System.out.println("Binary log of "+originalN+" is "+position);

Categories

Resources