Matrix with equal sum of rows and columns - algorithm

I have NxM matrix with integer elements, greater or equal than 0.
From any cell I can transfer 1 to another one (-1 to the source cell, +1 to the destination).
Using this operation, I have to make sums for all rows and columns equal. The question is how to find the minimal amount of such operations to achieve my task. During the processing cells may be negative.
For example, for
1 1 2 2
1 0 1 1
0 0 1 1
1 1 1 2
The answer is 3.
P.s.: I've tried to solve it on my own, but came only to brute-force solution.

First, find the expected sum per row and per column 1.
rowSum = totalSum / numRows
colSum = totalSum / numCols
Then, iterate through the rows and the columns and compute the following values:
rowDelta = 0
for each row r
if sum(r) > rowSum
rowDelta += sum(r) - rowSum
colDelta = 0
for each col c
if sum(c) > colSum
colDelta += sum(c) - colSum
The number of the minimum moves to equilibrate all the rows and columns is:
minMoves = max(rowDelta, colDelta)
This works because you have to transfer from rows that exceed rowSum into rows that don't exceed it, and from columns that exceed colSum into columns that don't exceed it.
If initially rowDelta was lower than colDelta, then you will attain a stage where you equilibrated all the rows, but the columns are still not equilibrated. At this case, you will continue transferring from cells to other cells in the same row. The same applies if initially colDelta was lower than rowDelta, and that's why we selected the maximum between them as the expected result.
1 If totalSum is not a multiple of numRows or numCols, then the problem has no solution.

Let us consider the one dimensional case: you have an array of numbers and you are allowed a single operation: take 1 from the value of one of the elements of the array and add it to other element. The goal is to make all elements equal with minimal operations. Here the solution is simple: you choose random "too big number" and add one to random "too small" number. Let me now describe how this relates to the problem at hand.
You can easily calculate the sum that is needed for every column and every row. This is the total sum of all elements in the matrix divided by the number of columns or rows respectively. From then on you can calculate which rows and columns need to be reduced and which - increased. see here:
1 1 2 2 -2
1 0 1 1 +1
0 0 1 1 +2
1 1 1 2 -1
+1+2-1-2
Expected sum of a row: 4
Expected sum of a column: 4
So now we generate two arrays: the array of displacements in the rows: -2,+1,+2,-1 and the number of displacements in the columns: +1,+2,-1,-2. For this two arrays we solve the simpler task described above. It is obvious that we can not solve the initial problem in fewer steps than the ones required for the simpler task (otherwise the balance in the columns or rows will not be 0).
However I will prove that the initial task can be solved in exactly as many steps as is the maximum of steps needed to solve the task for the columns and rows:
Every step in the simpler task generates two indices i and j: the index from which to subtract and the index to which to add. Lets assume in a step in the column task we have indices ci and cj and in the row task we have indices ri and rj. Then we assign a correspondence of this in the initial task: take 1 from (ci, ri) and add one to (cj, rj). At certain point we will reach a situation in which there might be still more steps in, say, the columns task and no more in the rows task. So we get ci and cj, but what do we do for ri and rj? We just choose ri=rj so that we do not screw up the row calculations.
In this solution I am making use of the fact I am allow to obtain negative numbers in the matrix.
Now lets demonstrate:
Solution for columns:
4->1;3->2;4->2
Solution for rows:
1->3;1->3;2->4
Total solution:
(4,1)->(1,3);(3,1)->(2,3);(4,2)->(2,4)

Supose thar r1 is the index of a row with maximal sum, while r2 is the row with minimal sum. c1 column with maximal sum and c2 column with minimal.
You need to repeat the following operation:
if Matrix[r1][c1] == Matrix[r2][c2] we're done!
Otherwise, Matrix[r1][c1] -= 1 and Matrix[r2][c2] += 1

Related

How to optimize search of rows x columns combination in a matrix?

Given a matrix of 1's and 0's, I want to find a combination of rows and columns with least or none 0's, maximizing the n_of_rows * n_of_columns picked.
For example, rows (0,1,2) and columns (0,1,3) have only one zero in col #0 row #1, and the rest 8 values are 1's.
1 1 0 1 0
0 1 1 1 0
1 1 0 1 1
0 0 1 0 0
Pracical task is to search over 1000's to 1000000's of rows and columns, finding the maximal biclique in a bipartite graph – rows and cols can be viewed as verticles, and values as connections.
The problem in NP-complete, as far as I learned.
Please advice an approach / algorithm that would speed up the task and reduce requirements to CPU and memory.
Not sure you could minimise thism
However, easy way to work this out would be...
Multiple your matrix by a 1 column and n rows full of 1's. This will give you number of ones in each row. Next do a 1 row by n columns multiplcation (at frot of) your matrix full of 1's. This will give you totals of 1's for each column, From there it's a pretty easy compairson........
ie original matrix...
1 0 1
0 1 1
0 0 0
do
1 0 1 x 1 = 2 (row totals)
o 1 1 1 2
0 0 0 1 0
do
1 1 1 x 1 0 1 = 1 (Column totals)
0 1 1 2
0 0 0 0
nb max sum is 2 (which you would keep track of as you work it out.
Actually given the following assumptions:
1. You don't care how many 0's are in each row or column
2. You don't need to keep track of their order....
Then you only really need to store values to count the total in each row/column as you read the values in and don't actually store the matrix itself.
If you are given the number of rows and columns prior to reading in the matrix you can do the following heuristics to reduce computational time...
Keep track of the current max. If the current row cannot reach this potential max stop counting for the row (but continue in the columns). Vice versa is true for the columns
But you still have a worst case scenario in which all rows and columns have sme number of 1's and 0's.... :)

Datalog-find duplicates

I would like to create a constraint that filters all duplicate rows in a nxn matrix, where every field consists of either 0 or 1. The matrix can be up to 10x10 rows and columns.
E.g. we have the following 4x4 matrix:
0 1 0 1
1 1 1 0
0 1 0 1
1 0 1 1
Then row 1 and row 3 would be identical which should not be possible. I've been thinking for 4 hours now about this problem, but with no luck.
Can someone give me a hint please?
As you're note, you can't "just" get the row (1,0,1,1) to occur twice in a datalog relation. The issue is, of course, that datalog relations store sets as opposed to lists or multisets of elements. The best way to deal with this is to add extra data to track either how often a row occurs to treat the matrix as map from indices to values. You might try one for the following:
myUnorderedMultiset[x,y,z,w]=count -> int(x), int(y), int(z), int(w), int(count).
or
myMatrix[rowIndex, columnIndex] = value -> int(rowIndex), int(columnIndex), int(value).

Nullify a 2D matrix with some set of operations

Given an N x M matrix having only positive integer values, we have to nullify the matrix
i.e make all entries 0.
We are given two operations
1) multiply each element of any one column at a time by 2.
2) Subtract 1 from all elements of any one row at a time
Find the minimum number of operations required to nullify the matrix.
i thought of doing something related to LCM but could not reach to a solution
Let's first solve for 1 row first and we can extend it to all rows. Let's take a random example:
6 11 5 13
The goal is to make all elements as 1. First we make 5 (smallest element) as 1. For this we need to subtract 4 (i.e subtract 1 four times). The resultant array is:
2 7 1 9
Now we multiply 1 with 2 and subtract all row elements by 1:
1 6 1 8
Next, we multiply 2 1's by 2 and subtract all row elements by 1:
1 5 1 7
Continuing in this manner, we get to 1 1 1 1. Now we subtract 1 to get 0 0 0 0.
Next, we get to other rows and do the same like above. The row we nullified above are all zeroes so multiplication by 2 when manipulating other rows doesn't change the already nullified rows.
The question of finding the minimum number of operations would also depend on the row sequence we select. I think that would be to select a row whose maximum is minimum (among other rows) first. I need to verify this.

How to display unique numbers with their frequencies as occurring in a matrix?

I have a matrice with some number:
1 2 3 6
6 7 2 1
1 4 5 6
And the program should display all different number with own frequency for example:
1 -> 3
2 -> 2
3 -> 1
4 -> 1
5 -> 1
6 -> 3
7 -> 1
Please help me
You probably mean
1->3
Create vector (array), filled with zeros, that have size of max value in matrice (like [0..9]), travell by whole matrice and with every step increment index of vector that equals actual number.
This is soluction for short range values in matrice. If you excpect some big values, use joined list insted of vector, or matrice like this for counting:
1 0
5 0
15 0
142 0
2412 0
And increment values in second column and expand this matrice rows every time you find a new number.
Using pointers this problem reduces from matrix to a single dimensional array. Maintain a 1D array whose size is equal to the total no. of elements in the matrix, say it COUNT. Initialize it with zero. Now start with first element of the matrix and compare it with all the other elements. If we use pointers this problem transforms into traversing a 1D array and finding the no of occurrences of each element. For traversing all you have to do is just increment the pointer. While comparing when you encounter the same number just shift forward all the consecutive numbers one place ahead. For example, if 0th element is 1 and you again found 1 on 4th index, then shift forward element on 5th index to 4th, 6th to 5th and so on till the last element. This way the duplicate entry at 4th index is lost. Now decrease the count of total no of elements in the matrix by 1 and increase the corresponding entry in array COUNT by 1. Continuing this way till the last element we get a matrix with distinct nos. and their corresponding frequency in array COUNT.
This implementation is very effective for languages which support pointers.
Here's an example of how it could be done in Python.
The dict is of this format: {key:value, key2:value2}. So you can use that so you have something like {'2':3} so it'll tell you what number has how many occurances. (I'm not assuming you're going to use Python. It's just so you understand the code... maybe)
matrix = [[1,5,6],
[2,6,3],
[5,3,9]]
dict = {}
for row in matrix:
for column in row:
if str(column) in dict.keys():
dict[str(column)] += 1
else:
dict[str(column)] = 1
for key in sorted(dict.keys()):
print key, '->', dict[key]
I hope you can figure out what this does. This codepad shows the output and nice syntax hightlighting.
(I don't get why SO isn't aligning the code properly... it's monospaced but not aligned :S ... turns out it's because I was using IE6 (It's the only browser at work :-(

Monotonically increasing 2-d array

Give an algorithm to find a given element x (give the co-ordinates), in an n by n matrix where the rows and columns are monotonically increasing.
My thoughts:
Reduce problem set size.
In the 1st column, find the largest element <= x. We know x must be in this row or after (lower). In the last column of the matrix, find the smallest element >= x. We know x must be in this row or before. Do the same thing with the first and last rows of the matrix. We have now defined a sub-matrix such that if x is in the matrix at all, it is in this sub-matrix. Now repeat the algo on this sub-matrix... Something along these lines.
[YAAQ: Yet another arrays question.]
I think you cannot hope for more than O(N), which is attainable. (N is the width of the matrix).
Why you cannot hope for more
Imagine a matrix like this:
0 0 0 0 0 0 ... 0 0 x
0 0 0 0 0 0 ... 0 x 2
0 0 0 0 0 0 ... x 2 2
.....................
0 0 0 0 0 x ... 2 2 2
0 0 0 0 x 2 ... 2 2 2
0 0 0 x 2 2 ... 2 2 2
0 0 x 2 2 2 ... 2 2 2
0 x 2 2 2 2 ... 2 2 2
x 2 2 2 2 2 ... 2 2 2
where x is an unknown number (not the same number, ie. it might be a different one in every column). To satisfy the monotonicity of the matrix, you can place any of 0, 1, or 2 in all of the x places. So, to find if there is 1 in the matrix, you have to check all the x places, and there are N of them.
How to make it O(n)
Imagine you have to find first column indicies with number > q (a given number) for all rows. You start in the upper right corner of the matrix; if the number you see is greater, you go left; else go down. End when you are in the last row. The points where you went down are the places you search for. If any of them have the number you search for, you've found it.
This algorithm is O(n), because in each step, you either go left or down. Totally, it cannot go more than N times left and N times down. Therefore it's O(n).
Pick a corner element, one that is greatest in its row and smallest in its column (or the other way). Compare with x. Depending on the result of the comparison, you can exclude the row or the column from further search.
The new matrix has sum of dimensions decreased by 1, compared to the original one. Apply the above iteratively. After 2*n steps you end up with a 1x1 matrix.
If "the rows and columns are monotonically increasing" means that the values in each (row,col) increase such that for any row, (rowM,col1) < (rowM,col2) < ... < (rowM,colN) < (rowM+1,col1) ...
Then you can just treat it as a 1 dimensional array that is sorted from smallest to largest, and do a standard binary search, by sampling the item that is 1/2(rows * cols) fron the start, then sampling the element that is 1/4(rows * cols) behind (if the first element sampled is > x) or ahead (if the first element sampled is < x), and so forth.

Resources