Picking two different random numbers fast - algorithm

Sometimes one requires random numbers with the condition that they are unique.
The classic algorithm is to keep looping until you hit the different numbers by chance, some pseudo code:
minval = 0 ;
maxval = 4 ; // random max will be one less than maxval
val1 = random( minval , maxval ) ;
val2 = random( minval , maxval ) ;
while( val1 == val2 ) {
val2 = random( minval , maxval ) ;
}
I have a time critical and memory limited program and was wondering if there are any algorithms that avoid the continuous loop brute force method without using extra memory like a look up table.
Probably a simple solution but it's a late and tired evening here.
Any tips?

Yes, you can exclude the already found number like this:
minval = 0 ;
maxval = 4 ; // random max will be one less than maxval
val1 = random( minval , maxval ) ;
val2 = random( minval , maxval - 1 ) ;
if(val2 >= val1) val2++;
The second time, specify an interval of one less than the first one, and shift the part above the already found number up by one.

Related

Partitioning a 2D matrix

Consider the following 2D matrix:
0,0,0,0,0
0,0,1,0,0
0,0,0,1,0
0,0,0,0,0
I could do only horizontal or vertical cuts stretching from end to end edges.
What could be the algorithm to use so I could find out how many times I can divide the matrix in 2 parts such that each of the 2 parts get equal number of cells with 1?
I assume you can do only one horizontal cut or vertical cut.
One approach for "one single matrix" is: ( You need to repetitively apply this to each partition you get ).
compute number of ones in each row and number of ones in each column, store them in two arrays like
OnesInRow[num_rows] , OnesInColumn[num_cols]
Also compute the total number of 1s in the matrix which is actually sum of values of all elements in either of the above arrays.
total = Sum( All elements in OnesInRow )
For example, you can get the number of ones in row number 2 like OnesInRow[1] ( assuming row index starts from 0 ). Similarly number of ones in col number 3 is OnesInCol[2].
Now consider a horizontal cut like this:
0,0,0,0,0
0,0,1,0,0
0,0,0,1,0
0,0,0,0,0
The number of ones that you get in each partition is : OnesInRow[0], Total - OnesInRow[0]
For this:
0,0,0,0,0
0,0,1,0,0
0,0,0,1,0
0,0,0,0,0
it is: Total - ( OnesInRow[0] + OnesInRow[1] ) , OnesInRow[0] + OnesInRow[1]
For this:
0,0, | 0,0,0
0,0, | 1,0,0
0,0, | 0,1,0
0,0, | 0,0,0
it is: Total - (OnesInCol[0] + OnesInCol[1] ), OnesInCol[0] + OnesInCol[1]
So you just need to consider all row cuts and col cuts and take which of those cuts will lead to two equal partitions of ones.
int count = 0;
int prevOnes = 0;
int onesInRowAboveThisCut = 0;
for ( int i = 1; i < rows; i++ ) {
onesInRowAboveThisCut = prevOnes + OnesInRow[i-1];
if ( onesInRowAboveThisCut= total/2 ) count++;
prevOnes = onesInRowAboveThisCut;
}
prevOnes = 0;
int onesInColBeforeThisCut = 0;
for ( int i = 1; i < cols; i++ ) {
onesInColBeforeThisCut = prevOnes + OnesInCol[i-1];
if ( onesInColBeforeThisCut = total/2 ) count++;
prevOnes = onesInColBeforeThisCut ;
}
return count;
Then for each matrix you get from such a partition you could repeat the process recursively, until you cant cut i.e. there is only one element in the array.
At each recursion you maintain a count variable and update it.

Minizinc array sorting

Lets say I have an array declaration looking like this
array[1..5] of int: temp = [1,0,5,0,3];
Is there a way to initiate a new array looking the same as temp but without the 0's? The result would look like the following
[1,5,3]
or sort the array in such a way that the 0's would be either in the beginning or in the end of the array, which would be
[0,0,1,5,3]
or
[1,5,3,0,0]
Thanks
Even though Axel has answered this, I'll show another approach which - in my book is a little neater.
Case 1: the array ("temp") is a constant array.
Then one can simply write
array[int] of int: temp2 = [temp[i] | i in index_set(temp) where temp[i] != 0];
MiniZinc 2 (in contrast to version 1.*) don't need the size declaration if it can be calculated; it suffices to just use "array[int]". Also, "index_set" is used to be a little more general, e.g. to handle cases where the indices are from 0..4 (see the commented line).
Case 2: the array ("s") is an array of decision variables
If the array to handle is decision variables, we don't know (per definition) how many 0's there are and must rely on the alternative variant, namely to sort the array. One can then use the "sort" function, as shown in the model.
include "globals.mzn";
% constant
array[1..5] of int: temp = [1,0,5,0,3];
% array[0..4] of int: temp = array1d(0..4, [1,0,5,0,3]);
array[int] of int: temp2 = [temp[i] | i in index_set(temp) where temp[i] != 0];
% decision variables
array[1..5] of var int: s;
array[1..5] of var int: s2 = sort(s); % NOT CORRECT, see model below
solve satisfy;
constraint
s = [1,0,5,0,3]
;
% show our variables
output
[
"temp: \(temp)\n",
"temp2: \(temp2)\n",
"s: \(s)\n",
"s2: \(s2)\n",
];
Update
For the stable version of decision variables, this works what I can see. It calculating the position where to place this number depending on if "s[i]" is 0 or not. Not very pretty though.
int: n = 5;
array[1..n] of var 0..5: s;
array[1..n] of var lb_array(s)..ub_array(s): s2;
solve satisfy;
constraint
s = [1,0,5,0,3] /\
forall(i in 1..n) (
if s[i] != 0 then
s2[sum([s[j]!=0 | j in 1..i-1])+1] = s[i]
else
s2[sum([s[j]!=0 | j in 1..n]) + sum([s[j]=0 | j in 1..i-1])+1 ] = 0
endif
)
;
output
[
"s: \(s)\n",
"s2: \(s2)\n",
]
;
The output is
s: [1, 0, 5, 0, 3]
s2: [1, 5, 3, 0, 0]
Using MiniZinc 2, this can be done as follows:
array[1..5] of int: temp = [1,0,5,0,3];
% calculate upper bound of temp index
int: i_max = max(index_set(temp));
% use array comprehension to count non-zero elements
int: temp_non_zero = sum([1 | i in 1..i_max where temp[i] != 0]);
% copy non-zero elements to new array
array[1..temp_non_zero] of int: temp2 = [temp[i] | i in 1..i_max where temp[i] != 0];
% calculate upper bound for temp2 index
int: i2_max = max(index_set(temp2));
solve satisfy;
% show our variables
output
["\ni_max=" ++ show(i_max)]
++ ["\ni2_max=" ++ show(i2_max)]
++ ["\n" ++ show(temp2[i]) | i in 1..i2_max]
;
Another alternative:
A 1:1 mapping between the two arrays is established as an array of unique index values (= array positions). These indices are then sorted. The comparison weights elements higher if they point to a zero. Thus, the zero values are shifted to the back while leaving the order of the non-zero elements unchanged.
int: n = 5;
int: INF = 99999; % infinity
array[1..n] of var 0..5: s;
array[1..n] of var 1..n: map;
array[1..n] of var 0..5: s2;
solve satisfy;
% set s[]
constraint
s = [1,0,5,0,3]
;
% 1:1 mapping between s[] and s2[]
constraint
forall (i in 1..n) (
exists(j in 1..n) (
map[j] = i
)
)
;
constraint
forall(i in 1..n) (
s2[i] = s[map[i]]
)
;
% sort the map and move zero values to the back
constraint
forall(i in 1..n-1) (
(if s2[i] != 0 then map[i] else INF endif) <=
(if s2[i+1] != 0 then map[i+1] else INF endif)
)
;
output
[
"s: \(s)\n",
"map: \(map)\n",
"s2: \(s2)\n",
]
;
Output:
s: [1, 0, 5, 0, 3]
map: [1, 3, 5, 4, 2]
s2: [1, 5, 3, 0, 0]

remove contiguous subarray to leave the average minimum

This problem appeared in some regional contest for ICPC.
Given n numbers, you have to remove numbers between i to j such that remaining numbers have least average. You can't remove first and last numbers.
2 <= n <= 10^5
We had a discussion about it, and I am still not able to understand it. Some how this problem can be converted to finding contiguous subarray with maximum sum and then it was solved with binary search in O(nlog n).
I couldn't catch that solution while discussion and now after thinking a lot I am not able to understand that solution.
Link to the original problem in case it's not clear: http://programmingteam.cc.gatech.edu/contest/Mercer14/problems/6.pdf
Here is an approach that I think might work:
Compute the partial average from left for all elements, with and updating average, this can be done in O(N): a_L(i) = (a_L(i-1)*(i-1) + a_L(i))/i
Do the same for the partial averages from the right: a_R(i) = (a_R(i+1)*(N-i) + a_R(i))/(N-i+1)
Find the minimum in of both lists.
If the minimum is in the left partial averages (a_L), look for the minimum right to it in the a_R and the other way around if the minimum is found in a_R.
All parts take O(N). Thus, this would result in an O(N) algorithm. Though, it sounds a little bit simple and I might be missing something.
Edit: The original answer stopped in the middle for both lists, which is insufficient on second thought.
Actually, if the minima overlap, I believe, there is no interval to cut out. Here is a little Python implementation of the algorithm:
grades = [5, 5, 1, 7, 8, 2]
N = len(grades)
glob_avg = float(sum(grades))/float(N)
print('total average: {0}'.format(glob_avg))
avg_L = grades[:]
avg_R = grades[:]
minL = 0
minR = N-1
for i in range(1,N):
avg_L[i] = float(avg_L[i-1]*i + grades[i])/float(i+1)
if avg_L[i] <= avg_L[minL]:
minL = i
avg_R[N-i-1] = float(avg_R[N-i]*i + grades[N-i-1])/float(i+1)
if avg_R[N-i-1] <= avg_R[minR]:
minR = N-i-1
opti_avg = glob_avg
if minL < minR:
first = minL+1
last = minR
opti_avg = (avg_L[first-1]*first + avg_R[last]*(N-last)) / float(N + first - last)
print('')
print('Interval to cut: {0} - {1}'.format(first,last))
for pre in grades[:first]:
print('{0}'.format(pre))
for cut in grades[first:last]:
print('X {0} X'.format(cut))
for post in grades[last:]:
print('{0}'.format(post))
else:
print('NO interval found that would reduce the avg!')
print('')
print('--------------------------------------')
print('minimal avg: {0:0.3f}'.format(opti_avg))
print('--------------------------------------')
I would try checking each value above the global minimum, starting with largest.
You can add to left or right (whichever is largest), as long as the average is above the global average.
Keep a note of any minimums to remaining items.
For each item >= global average
While( average( selected) > global average
If average(un selected items) < best so far
Best so far = selected range
End
Add to selection largest of left and right
End while
End for
Only by finding sequences which are above the average will a minimum for unselected work.
Any item which has been considered as a list can be discounted
Had a go at implementing in Python :-
lst = [ -1, -1,1,-90,1,3,-1,-1,1,2,3,1,2,3,4,1, -1,-1];
First solution - look really at an exhausitve test - allow me to verify correctness.
lbound = 0
ubound = len( lst)
print( ubound );
# from http://math.stackexchange.com/questions/106700/incremental-averageing
def Average( lst, lwr, upr, runAvg = 0, runCnt = 0 ):
cnt = runCnt;
avg = runAvg;
for i in range( lwr, upr ):
cnt = cnt + 1
avg = float(avg) + (float(lst[i]) - avg)/cnt
return (avg, cnt )
bestpos_l = 0
bestpos_u = 0
bestpos_avg = 0
best_cnt = 0
######################################################
# solution in O(N^2) - works always
for i in range( 1, len( lst ) - 1 ):
for j in range( i+1, len(lst ) ):
tpl = Average( lst, 0, i ) # get lower end
res = Average( lst, j, len(lst), tpl[0], tpl[1] )
if (best_cnt == 0 or
(best_cnt < res[1] and res[0] == bestpos_avg ) or
res[0] < bestpos_avg ):
bestpos_l = i
bestpos_u = j
bestpos_avg = res[0]
best_cnt = res[1]
print( "better", i,j, res[0], res[1] )
print( "solution 1", bestpos_l, bestpos_u, bestpos_avg, best_cnt )
This came up with valid answers, but I hadn't appreciated, with the current data set, it doesn't really want the right hand side.
########################################################
# O(N)
#
# Try and minimize left/right sides.
#
# This doesn't work - it knows -90 is really good, but can't decide if to
# ignore -90 from the left, or the right, so does neither.
#
lower = []
upper = []
lower_avg = 0
best_lower = lst[0]
lower_i = 0
best_upper = lst[-1]
upper_avg = 0
upper_i = len(lst) -1
cnt = 0
length = len(lst)
for i in range( 0, length ):
cnt = cnt + 1
lower_avg = float( lower_avg) + ( float(lst[i]) - lower_avg)/cnt
upper_avg = float( upper_avg) + ( float(lst[-(i+1)]) - upper_avg)/cnt
upper.append( upper_avg )
lower.append( lower_avg )
if lower_avg <= best_lower:
best_lower = lower_avg
lower_i = i
if upper_avg <= best_upper:
best_upper = upper_avg
upper_i = (len(lst) - (i+1))
if( lower_i + 1 > upper_i ):
sol2 = Average( lst,0, len(lst ))
else:
sol_tmp = Average( lst,0, lower_i+1 )
sol2 = Average( lst, upper_i, len(lst),sol_tmp[0],sol_tmp[1] )
print( "solution 2", lower_i + 1, upper_i, sol2[0],sol2[1] )
The third solution was what I was trying to explain. My implementation is limited because :-
Couldn't find a good way of finding starting points. I wanted to start from the biggest elements, as they are most likely to reduce the average, but haven't got a good way of finding them.
Wasn't sure about the stability of keeping running-averages. Thought about removing items from the average by un-doing each numbers effect. Wasn't sure how this affected precision.
Was fairly sure that any interval which has been checked, can't have a starting item. That would limit further work, but unsure how best to implement such (keeping O(xx) to a minimum.
Solution 3
#################################
## can we remove first / last? if so, this needs adjusting
def ChooseNext( lst, lwr, upr ):
if lwr > 1 and upr < len(lst) -2:
# both sides available.
if lst[lwr-1] > lst[upr]:
return -1
else:
return 1
elif lwr > 1:
return -1
elif upr < len(lst) -2:
return 1
return 0
# Maximize average of data removed.
glbl_average = Average( lst, 0, len(lst) )
found = False
min_pos = 0
max_pos = 0
best_average = glbl_average[0]
for i in range(1, len(lst ) - 1):
# ignore stuff below average.
if lst[i]> glbl_average[0] or (found == False ):
lwr = i
upr = i+1
cnt = 1 # number for average
avg = lst[i]
tmp = Average( lst, 0, lwr)
lcl = Average( lst, upr, len(lst ), tmp[0], tmp[1] )
if found == False or lcl[0] < best_average:
best_average = lcl[0]
min_pos = lwr
max_pos = upr
found = True
# extend from interval (lwr,upr]
choice = ChooseNext( lst, lwr, upr )
while( choice != 0 ):
if( choice == -1):
new_lwr = lwr -1
new_upr = upr
else:
new_lwr = lwr
new_upr = upr + 1
tmp = Average( lst, 0, new_lwr )
lcl_best = Average( lst, new_upr, len(lst), tmp[0], tmp[1] )
if( lcl_best[0] > glbl_average[0]):
choice = 0
else:
lwr = new_lwr
upr = new_upr
if lcl_best[0] < best_average:
min_pos = lwr
max_pos = upr
best_average = lcl_best[0]
choice = ChooseNext( lst, lwr, upr )
print( "solution 3", min_pos, max_pos, best_average )

Trouble implementing North-East Paths with recursion

I'm supposed to use recursion to output the total number of unique north-east paths ne(x, y) to get from point A to point B, where B is x rows north and y columns east of A. In addition, I am required to print the possible unique NE paths.
I know how to use recursion to get the total number of unique paths. However, I am stuck with using recursion to print all the NE paths correctly.
This is the given output of some test cases:
image of output
Anyway, here's a screenshot of my faulty recursive code.
Please do give me advice where I went wrong. I have been burning a lot of time on this, but still I can't reach a solution.
I think you should print if( rows == 0 && cols == 0 ), because it's the case when you've reached point B.
Why are you using path+="N" in the first ne call in return? this will add "N" to original path and then you'll get path+"N"+"E" in the second call.
Try following:
public static int ne( int rows, int cols, String path )
{
if( rows == 0 && cols == 0 )
{
System.out.println(path);
return 1;
}
int npats = 0, wpaths = 0;
if( rows != 0 )
npaths = ne( rows-1, cols, path+"N" );
if( cols != 0 )
wpaths = ne( rows, cols-1, path+"E" );
return npaths + wpaths;
}

How to calculate center of gravity in grid?

Given a grid (or table) with x*y cells. Each cell contains a value. Most of these cells have a value of 0, but there may be a "hot spot" somewhere on this grid with a cell that has a high value. The neighbours of this cell then also have a value > 0. As farer away from the hot spot as lower the value in the respective grid cell.
So this hot spot can be seen as the top of a hill, with decreasing values the farer we are away from this hill. At a certain distance the values drop to 0 again.
Now I need to determine the cell within the grid that represents the grid's center of gravity. In the simple example above this centroid would simply be the one cell with the highest value. However it's not always that simple:
the decreasing values of neighbour cells around the hot spot cell may not be equally distributed, or a "side of the hill" may fall down to 0 sooner than another side.
there is another hot spot/hill with values > 0 elsewehere within the grid.
I could think that this is kind of a typical problem. Unfortunately I am no math expert so I don't know what to search for (at least I have not found an answer in Google).
Any ideas how can I solve this problem?
Thanks in advance.
You are looking for the "weighted mean" of the cell values. Assuming each cell has a value z(x,y), then you can do the following
zx = sum( z(x, y) ) over all values of y
zy = sum( z(x, y) ) over all values of x
meanX = sum( x * zx(x)) / sum ( zx(x) )
meanY = sum( y * zy(y)) / sum ( zy(y) )
I trust you can convert this into a language of your choice...
Example: if you know Matlab, then the above would be written as follows
zx = sum( Z, 1 ); % sum all the rows
zy = sum( Z, 2 ); % sum all the columns
[ny nx] = size(Z); % find out the dimensions of Z
meanX = sum((1:nx).*zx) / sum(zx);
meanY = sum((1:ny).*zy) / sum(zy);
This would give you the meanX in the range 1 .. nx : if it's right in the middle, the value would be (nx+1)/2. You can obviously scale this to your needs.
EDIT: one more time, in "almost real" code:
// array Z(N, M) contains values on an evenly spaced grid
// assume base 1 arrays
zx = zeros(N);
zy = zeros(M);
// create X profile:
for jj = 1 to M
for ii = 1 to N
zx(jj) = zx(jj) + Z(ii, jj);
next ii
next jj
// create Y profile:
for ii = 1 to N
for jj = 1 to M
zy(ii) = zy(ii) + Z(ii, jj);
next jj
next ii
xsum = 0;
zxsum = 0;
for ii = 1 to N
zxsum += zx(ii);
xsum += ii * zx(ii);
next ii
xmean = xsum / zxsum;
ysum = 0;
zysum = 0;
for jj = 1 to M
zysum += zy(jj);
ysum += jj * zy(ii);
next jj
ymean = ysum / zysum;
This Wikipedia entry may help; the section entitled "A system of particles" is all you need. Just understand that you need to do the calculation once for each dimension, of which you apparently have two.
And here is a complete Scala 2.10 program to generate a grid full of random integers (using dimensions specified on the command line) and find the center of gravity (where rows and columns are numbered starting at 1):
object Ctr extends App {
val Array( nRows, nCols ) = args map (_.toInt)
val grid = Array.fill( nRows, nCols )( util.Random.nextInt(10) )
grid foreach ( row => println( row mkString "," ) )
val sum = grid.map(_.sum).sum
val xCtr = ( ( for ( i <- 0 until nRows; j <- 0 until nCols )
yield (j+1) * grid(i)(j) ).sum :Float ) / sum
val yCtr = ( ( for ( i <- 0 until nRows; j <- 0 until nCols )
yield (i+1) * grid(i)(j) ).sum :Float ) / sum
println( s"Center is ( $xCtr, $yCtr )" )
}
You could def a function to keep the calculations DRYer, but I wanted to keep it as obvious as possible. Anyway, here we run it a couple of times:
$ scala Ctr 3 3
4,1,9
3,5,1
9,5,0
Center is ( 1.8378378, 2.0 )
$ scala Ctr 6 9
5,1,1,0,0,4,5,4,6
9,1,0,7,2,7,5,6,7
1,2,6,6,1,8,2,4,6
1,3,9,8,2,9,3,6,7
0,7,1,7,6,6,2,6,1
3,9,6,4,3,2,5,7,1
Center is ( 5.2956524, 3.626087 )

Resources