Wrapping around a grid with modulo - c++

I am trying to write a program that implements Conway's Game of Life on a grid of 20x60 cells. The grid should wrap around so that the left side is connected to the right side and the top is connected to the bottom.
Thus, any cell with position (0, col), will have a neighbour at (maxRow, col). Any cell with position (row, 0) will have a neighbour at (row, maxCol).
The following function is supposed to count the number of neighbouring cells. It works for coordinates not on the edges, but not for ones that are. For instance, if there are points at (0, 10), (0, 11), (0, 12), and (0, 10) is passed into the function, it will return a high number as neighbour count instead of 1. I know that the mod operator % would be helpful, but I don't understand how to use it.
{
int i, j;
int count = 0;
for (i = row - 1; i <= row + 1; i++)
for (j = col - 1; j <= col + 1; j++)
count += grid[i][j]; }
if (row==maxrow-1 || row==0)
count = count+ grid [(row-(maxrow-1))*-1][col-1]+grid[(row-(maxrow-1))*-1][col]+grid[(row-(maxrow-1))*-1][col+1];
if (col==0 || col==maxcol-1)
count=count +grid[row-1][(col-(maxcol-1))*-1]+grid[row][(col-(maxcol-1))*-1]+grid[row+1][(col-(maxcol-1))*-1];
count -= grid[row][col];
return count;
}

Before offering a solution, let me make some observations.
Adding up some grid values and later subtracting other grid values is not a good idea. You should calculate the correct grid coordinates to begin with.
When you write count += grid[i][j];, you are using array indices that may be invalid. For example, i = row - 1 when row is zero yields an i value of -1.
Your code implies that maxrow is the number of rows because you're writing maxrow-1, but the name maxrow suggests a maximum row index. This is confusing. It would be better to call the number of rows numRows, and then the greatest row index is numRows - 1. Likewise, it would be better to replace maxcol with numCols.
Now to the heart of the matter. The value row - 1 can be equal to -1, and row + 1 can be equal to numRows. Both of these are invalid row indices. Similarly, col - 1 and col + 1 can result in the invalid column indices -1 and numCols. One way to solve the problem is to test for these particular values and replace them with wraparound indices:
int count = 0;
for (int i = row - 1; i <= row + 1; i++) {
int R = i;
if (R == -1) {
R = numRows - 1;
} else if (R == numRows) {
R = 0;
}
for (int j = col - 1; j <= col + 1; j++) {
if (i == row && j == col) {
continue; // Skip grid[row][col].
}
int C = j;
if (C == -1) {
C = numCols - 1;
} else if (C == numCols) {
C = 0;
}
count += grid[R][C];
}
}
That's a high-performance way to solve the problem because testing and assignment are faster operations than modulo, but it's also a lot of code. We can write more concise code with the help of the modulo operator.
We would like to write i % numRows, except C++ evaluates this as -1 when i is -1. That's because the modulo operation is ambiguous for negative values and C++ has chosen an interpretation that doesn't guarantee non-negative results.
To fix this problem, we add numRows to i before taking the modulo numRows. This ensures that we're always taking the modulo of a positive number. Now we can count the number of live cells among the eight neighbors of grid[row][col] as follows.
int count = 0;
for (int i = row - 1; i <= row + 1; i++) {
for (int j = col - 1; j <= col + 1; j++) {
if (i == row && j == col) {
continue; // Skip grid[row][col].
}
count += grid[(i + numRows) % numRows][(j + numCols) % numCols];
}
}

Related

Min sum of distances (absolute differences) between array element and set of k array elements

I need to find the minimum sum of the distances between an element in the array and the set of k-elements of the array, not including that index.
For example:
arr = {5, 7, 4, 9}
k = 2
min_sum(5) = |5-4| + |5-7| = 3
min_sum(7) = |7-9| + |7-5| = 4
min_sum(4) = |4-5| + |4-7| = 4
min_sum(9) = |9-7| + |9-5| = 6
So, a naive solution would be to subtract the i-th element from each element of the array, then sort the array and calculate the sum of the first k elements in the sorted array. But it takes too long... I believe this is a dp-problem or something like that (maybe treaps).
Input:
n - number of array elements
k - number of elements in a set
array
Constraints:
2 <= n <= 350 000
1 <= k < n
1 <= a[i] <= 10^9
time limit: 2 seconds
Input:
4
2
5 7 4 9
Output:
3 4 4 6
What is the most efficient way to solve this problem? How to optimize the search for the minimum sum?
This is my code in C++, and it works about 3 mins for n = 350 000, k = 150 000:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, k, tp;
unsigned long long temp;
cin >> n >> k;
vector<unsigned int> org;
vector<unsigned int> a;
vector<unsigned long long> cum(n, 0);
//unordered_map <int, long long> ans;
unordered_map <int, long long> mp;
for (int i = 0; i < n; i++){
cin >> tp;
org.push_back(tp);
a.push_back(tp);
}
/*
srand(time(0));
for (int i = 0; i < n; i++){
org.push_back(rand());
a.push_back(org[i]);
}
*/
sort(a.begin(), a.end());
partial_sum(a.begin(), a.end(), cum.begin());
mp[a[0]] = cum[k] - cum[0] - a[0] * k;
//ans[a[0]] = mp[a[0]];
for (int i = 1; i <= k; i++) {
mp[a[i]] = a[i] * i - cum[i-1] + cum[k] - cum[i] - a[i] * (k-i);
}
for (int i = 1; i < n-k; i++){
for (int j = 0; j <= k; j++){
//if (ans.find(a[i+j]) != ans.end()) {continue;}
temp = ( (a[i+j] * j) - (cum[i+j-1] - cum[i-1]) ) + ( cum[i+k] - cum[i+j] - a[i+j] * (k-j) );
if (mp.find(a[i+j]) == mp.end()) { mp[a[i+j]] = temp; }
else if (mp[a[i+j]] > temp) { mp[a[i+j]] = temp; }
//else { ans[a[i+j]] = mp[a[i+j]]; }
}
}
for (int i = 0; i < n; i++) {
cout << mp[org[i]] << " ";
}
return 0;
}
We can solve this problem efficiently by taking the sliding window approach.
It seems safe to assume that there are no duplicates in the array. If it contains duplicates, then we can simply discard them with the help of HashSet.
The next step is to sort the array to guarantee that the closest k elements will be within the window [i - k; i + k] for each index i.
We will keep three variables for the window: left, right and currentSum. They will be adjusted accordingly at each iteration. Initially, left = 0 and right = k(since the element at index 0 doesn't have elements to its left) and currentSum = result for index 0.
The key consideration is that the variables left and right are unlikely to change 'significantly' during the iteration. To be more precise, at each iteration we should attempt to move the window to the right by comparing the distances nums[i + right + 1] - nums[i] vs nums[i] - nums[i - left]. (You can prove mathematically that there is no point in trying to move the window to the left.) If the former is less than the latter, we increment right and decrement left while updating currentSum at the same time.
In order to recalculate currentSum, I would suggest writing down expressions for two adjacent iterations and looking closer at the difference between them.
For instance, if
result[i] = nums[i + 1] + ... + nums[i + right] - (nums[i - 1] + ... + nums[i - left]) + (left - right) * nums[i], then
result[i] = nums[i + 2] + ... + nums[i + right] - (nums[i] + ... + nums[i - left]) + (left - right + 2) * nums[i + 1].
As we can see, these expressions are quite similar. The time complexity of this solution is O(n * log(n)). (my solution in Java for n ~ 500_000 and k ~ 400_000 works within 300 ms) I hope this together with the consideration above will help you.
Assuming that we have sorted the original array nums and computed the mapping element->its index in the sorted array(for instance, through binary search), we can proceed with finding the distances.
public long[] findMinDistances(int[] nums, int k) {
long[] result = new long[nums.length];
long currentSum = 0;
for (int i = 1; i <= k; i++) {
currentSum += nums[i];
}
result[0] = currentSum - (long) k * nums[0];
int left = 0;
int right = k;
currentSum = result[0];
for (int i = 1; i < nums.length; i++) {
int current = nums[i];
int previous = nums[i - 1];
currentSum -= (long) (left - right) * previous;
currentSum -= previous;
if (right >= 1) {
currentSum -= current;
left++;
right--;
} else {
currentSum += nums[i - 1 - left];
}
currentSum += (long) (left - right) * current;
while (i + right + 1 < nums.length && i - left >= 0 &&
nums[i + right + 1] - current < current - nums[i - left]) {
currentSum += nums[i + right + 1] - current;
currentSum -= current - nums[i - left];
right++;
left--;
}
result[i] = currentSum;
}
return result;
}
For every element e in the original array its minimal sum of distances will be result[mapping.get(e)].
I think this one is better:
Sort the array first then you can know that fact -
For every element i in the array the k minimum distances of it with other elemets will be the distances with the ones that in k places around it in the array.
(of course it's maybe to the right or to the left or from both sides).
So for every element i to calculate min_sum(a[i]) do that:
First, min_sum(a[i]) = 0.
Then, go with two indexes, let's mark them r (to the right of i) and l (to the left of i)
and compare the distance (a[i]-a[r]) with the distance (a[i]-a[l]).
You will add the smallest to min_sum(a[i]) and if it was the right one then
increas index r, and if it was the left one then decrease index l.
Of course if the left got to 0 or the right one got to n you will most take the distaces with elemets from the other side.
Anyway you do that till you sum k elemets and that's it.
This way you didn't sort any thing but the main array.

Symmetric matrix, value into c++ vector

I am trying to solve the following problem. Let's say I have a symmetric matrix with size n. I want to take all the "important values", and store them into a vector. Let me give an example to explain it better.
Let's say I have the following matrix A = [1, 2, 3 // 2, 5, 6 // 3, 6, 9]. I want to define vector of size n*(n+1)/2 such that:
V = [A(0,0), A(0,1), A(0,2), A(1,1), A(1,2), A(2,2) ]
I want to find a function that receives as input two integer i and j, and outputs the corresponding value of the matrix. The catch is that I do not want to access the matrix directly, instead I want to access the vector.
This is my reasoning so far. If I have an input with j < i, I just swap them since the matrix is symmetric. If I have that i == 0, the position in the array is just j. If that is not the case, I think I need to do something like this. (n is the dimension of the matrix, and position is the integer that I need when for the array.)
int position = 0;
for(int k = 0; k < i; k++){
position = position + (n-k);
}
position = position + j % i;
However, this code fails. I think I'm close to the solution but I am missing something. Any help?
The last j % i should be j - i.
In addition, the loop is essentially doing
position = n + (n - 1) + ... + (n - i + 1);
which can be simplified to
position = (n * 2 - i + 1) * i / 2;
So you can simply write
position = (n * 2 - i + 1) * i / 2 + j - i;
or
position = (n * 2 - i - 1) * i / 2 + j;
You can do simply this:
int myvector[matrix.size()];
int pos = 0;
for(int i = 0; i < matrix.size(); i++){
for(int j = 0; j < matrix.size(); j++){
if(j > i) myvector[pos++] = matrix[i][j];
else myvector[pos++] = matrix[j][i];
}
}

How to turn equation with decrementing indexing into math equation with summation?

Similar to this question: Turn while loop into math equation?, I have the following nested loop that I am trying to convert into a math equation as I need to write this up in a format that doesn't look like code. I believe I am going to need some type of summation equation.
Here is the code:
int num = 0;
for (int i = nr - 1; i >= 0; i--) {
for (int j = nc - 1; j >= 0; j--) {
ela[i][j] = num;
eha[i][j] = num + ea[i][j] - 1;
num += ea[i][j];
}
}
I know that summations start from a lower bound and continue to a higher bound, so I'm not quite sure how to apply a summation here since I start from a higher index and continue to a lower index.
I'm not sure why I'm getting downvoted, as the question I referenced is very similar to mine, has the same tags and is upvoted 14 times. Please comment below if I can improve my question somehow.
Update:
I was able to update the formula as follows:
nr = 50;
nc = 10;
num = sum[ea[i,j],i=0,nr-1,j=0,nc-1]; // correct based upon nr, nc and ea
for (int i = 0; i < nr; i) {
for (int j = 0; j < nc; j++) {
num = num - ea[i,j];
ela[i][j] = num;
eha[i][j] = num + ea[i,j] - 1;
}
}
If I am right, you can transcribe the effect as
You can describe this as the matrix ela being a 2D suffix sum of the matrix ea (for every element, sum of the elements that follow in the lexicographical ordering), while eha is the sum of matrices ela and ea minus all ones.
If the problem is just with how to express the sum when you're looping the other direction, you can change your code to:
int num = 0;
for (int i = 0; i < nr; i++) {
for (int j = 0; j < nc; j++) {
ela[nr - i][nc - j] = num;
eha[nr - i][nc - i] = num + ea[nr - i][nc - j] - 1;
num += ea[nr - i][nc - j];
}
}
I'm not saying you have to change your code to this, but from here it should be more obvious how to change this to use summation notation.
It's hard to tell without any context, but the code in question becomes more intelligible if you think of the arrays as vectors enumerating the elements in reverse order, row-major. The code below is functionally equivalent to the original one posted, but arguably easier to follow.
// n.b. ela[nr - 1 - i][nc - 1 - j] == rela(nc * i + j);
int &rela(int k) { return ela[nr - 1 - k / nc][nc - 1 - k % nc]; }
int &reha(int k) { return elh[nr - 1 - k / nc][nc - 1 - k % nc]; }
int &rea(int k) { return ea[nr - 1 - k / nc][nc - 1 - k % nc]; }
for (int k = 0, sum = 0; k < nr * nc - 1; k++) {
rela(k) = sum;
sum += rea(k);
reha(k) = sum - 1;
}
In plain English, rela(k) is the partial sum of rea elements 0 ... k-1 and reha(k) is one less than the partial sum of rea elements 0 ... k (also, rela(k) == reha(k - 1) + 1 for k > 0).
Technically, this description could be translated back in terms of the 2d arrays, but it becomes rather messy quickly.

Maximum possible sum less than or equal to k in a 2D array using each row

Given : A two dimensional array , values K and M
Problem : Find the maximum possible sum less than or equal K using all the rows (i.e there should be an element form each row) using exactly M elements.
This is a snippet of a program, I am having trouble implementing the conditions for each row and M.
for (int i = 0 ; i<n ; i++)
for (int s=0; s<M; s++)
for (int j=K;j>=0;j--)
if (dp[s][j] && A[i] + j < K)
dp[s + 1][j + A[i]] = true;
EDIT 1: Rows = M , i.e one element from each row has to be selected.
EDIT 2 : Dynamic Programming Solution, Thanks to #6502
ill ret(V(ill) col[101],ill prec[][101],ill s,ill row,ill m,ill k)
{
if(prec[s][row])
return prec[s][row];
else
{
if(row==m+1)
return s;
ill best=-1;
int j=row;
for(int i=0;i<col[j].size();i++)
{
if(s+col[j][i] <= k)
{
ill x = ret (col,prec,s+col[j][i],row+1,m,k);
if ((best==-1)||(x>best))
best=x;
}
}
prec[s][row]=best;
return best;
}
}
The problem can be solved using dynamic programming by choosing as state the pair (s, row) where s is the current sum and row is the next row we need to include.
The maximal principle is valid because no matter on which choices we made in previous rows the result depends only on the current sum and the current row index.
In code (Python)
cache = {}
data = [[2, 3, 4],
[2, 3, 4],
[2, 3, 4]]
M = 3
K = 10
def msum(s, row):
try:
return cache[s, row]
except KeyError:
if row == M:
return s
best = None
for v in data[row]:
if s+v <= K:
x = msum(s+v, row+1)
if best is None or x > best:
best = x
cache[s, row] = best
return best
print msum(0, 0)
The function returns None if no solution exists (i.e. if even taking the smallest value from each row we end up exceeding K).
A brute force approach:
bool increase(const std::vector<std::vector<int>>& v, std::vector<std::size_t>& it)
{
for (std::size_t i = 0, size = it.size(); i != size; ++i) {
const std::size_t index = size - 1 - i;
++it[index];
if (it[index] > v[index].size()) {
it[index] = 0;
} else {
return true;
}
}
return false;
}
int sum(const std::vector<std::vector<int>>& v, const std::vector<std::size_t>& it)
{
int res = 0;
for (std::size_t i = 0; i != it.size(); ++i) {
res += v[i][it[i]];
}
return res;
}
int maximum_sum_less_or_equal_to_K(const std::vector<std::vector<int>>& v, int K)
{
std::vector<std::size_t> it(v.size());
int res = K + 1;
do {
int current_sum = sum(v, it);
if (current_sum <= K) {
if (res == K + 1 || res < current_sum) {
res = current_sum;
}
}
} while (increase(v, it));
if (res == K + 1) {
// Handle no solution
}
return res;
}
it has the current selection of each row.
This can be solved using boolean 2D table. The value of dp[r][s] is set to true, if its possible to generate sum 's' , using exactly 'r' rows (i.e exactly one element from each of the [0 to r-1] rows). Using this dp table, we can compute next state as
dp[r+1][s] |= dp[r][s-A[r+1][c]] ; 0 < c < N, 0 < s <= K
where N is number of columns(0-based indexing). Finally return the value of max index set in M-1 row of dp table
Following is a bottom-up implementation
// Assuming input matrix is M*N
int maxSum() {
memset(dp, false, sizeof(dp));
//Initialise base row
for (int c = 0; c < N; ++c)
dp[0][A[0][c]] = true;
for ( int r = 1; r < M; ++r ) {
for ( int c = 0; c < N; ++c) {
// For each A[r][c], check for all possible values of sum upto K
for (int sum = 0; sum <= K; ++sum) {
if ( sum-A[r][c] >= 0 && dp[r-1][sum-A[r][c]] )
dp[r][sum] = true;
}
}
}
// Return max possible value <= K
for (int sum = K; sum >= 0; --sum) {
if ( dp[M-1][sum] )
return sum;
}
return 0;
}
Note that dp table values for current row depend only on previous row, as such space optimization trick can be used to solve it using 1-D table

find sum of diagonal elements from given index in 2d array

I have to construct a 2d array with N,M rows and columns (N & M <= 5), then the user enters a certain index(location) like 2,3 (matrix[2][3]) it's assumed that the two numbers are in the bounds of the matrix. From then on I have to find the sum of the left and right diagonal that goes through the number, however the number is excluded from the sum.
So for example the 2d array is myArray[3][3]
*1* 15 *2*
2 *71* 8
*5* 22 *5*
So the user enters 1,1 that is myArray[1][1], in this case the number 71, the sum would be 1 + 5 + 2 + 5 ... And well my problem is how can i find those diagonals without going out of the bounds.
For the left top i would go:
row--
column--
while(row >= 0|| column >= 0)
For left bottom:
row++
colum++
while(row < N || column < M)
for right top:
row--
column++
while(row >= 0 || column < M)
for right bottom:
row++
column--
while(row < N || column >=0)
(this is bad written pseudo-code, sorry)
It works fine when I enter numbers that aren't in the top or bottom row, but in the cases that they are located there my program stops.
What you have is basically good pseudocode. My first thought was that you should be using &&'s instead of ||'s when determining if the location is out of bounds or not.
You also need some sort of way to exit early in case they give a bad location. Below is some code I wrote out quickly, and seems to work at a quick glance - I loop over every possible starting location including ones that are out of bounds.
#include <iostream>
const int N = 3;
const int M = 4;
int matrix[N][M] = {
{ 0, 1, 2, 3 },
{ 4, 5, 6, 7 },
{ 8, 9, 10, 11 }
};
int directional_sum(int row, int column, int row_inc, int column_inc)
{
int sum = 0;
if (row < 0 || column < 0 || row >= N || column >= M)
return sum;
int temp_row = row + row_inc;
int temp_column = column + column_inc;
while (temp_row >= 0 && temp_column >= 0 && temp_row < N && temp_column < M)
{
sum += matrix[temp_row][temp_column];
temp_row += row_inc;
temp_column += column_inc;
}
return sum;
}
int diagonal_sum(int row, int column)
{
int sum = 0;
sum += directional_sum(row, column, 1, 1);
sum += directional_sum(row, column, 1, -1);
sum += directional_sum(row, column, -1, 1);
sum += directional_sum(row, column, -1, -1);
return sum;
}
int main()
{
for (int i = -1; i <= N; i++)
{
for (int j = -1; j <= M; j++)
{
std::cout << "Sum for [" << i << ", " << j << "]: " << diagonal_sum(i, j) << std::endl;
}
}
return 0;
}