Unexpected result from i == j == k? - chapel

In this code I am looping over all indices in a 3D domain, and printing the "diagonal" part as
for (i, j, k) in {0..9, 0..9, 0..9}
{
if i == j == k // (1)
//if (i == j) && (j == k) // (2) -> gives expected result
{
writeln((i, j, k));
}
}
My expected result is something like
(0, 0, 0)
(1, 1, 1)
(2, 2, 2)
(3, 3, 3)
(4, 4, 4)
(5, 5, 5)
(6, 6, 6)
(7, 7, 7)
(8, 8, 8)
(9, 9, 9)
which is obtained with Line (2) above. But if I use Line (1), it gives an unexpected result like
(0, 0, 1)
(0, 1, 0)
(0, 2, 0)
...
(9, 7, 0)
(9, 8, 0)
(9, 9, 1)
So I am wondering if I am erroneously using i == j == k?
(FYI, the above code is motivated by some Python code like
for i in range(10):
for j in range(10):
for k in range(10):
if i == j == k:
print( i, j, k )
which gives (0, 0, 0), (1, 1, 1), ...)

Right on, #Someprogrammerdude.
== is a binary operator, it is left-associative. The documentation is here:
https://chapel-lang.org/docs/language/spec/expressions.html#precedence-and-associativity
When comparing the boolean (i==j) with the integer k (in the context of i==j==k), the boolean is implicitly converted to an integer and an integer equality check is performed.

FWIW, these are results that I got from other languages (but my usage of each language may be wrong, so please take it as such...).
C++
#include <iostream>
using namespace std;
int main() {
int i = 2, j = 2, k = 2;
cout << (i == j == k) << endl;
}
// => 0 (false), probably by interpreting it as (i == j) == k
Chapel
var i, j, k = 2;
writeln( i == j == k );
// => false (same as C++)
D
import std.stdio;
void main() {
int i = 2, j = 2, k = 2;
writeln( i == j == k );
}
// => Error: found == when expecting ) (and some related messages)
Rust
fn main() {
let i = 2;
let j = 2;
let k = 2;
println!( "{:?}", i == j == k );
}
// => Error
error: chained comparison operators require parentheses
--> test.rs:6:25
|
6 | println!( "{:?}", i == j == k );
| ^^^^^^^^^
error[E0308]: mismatched types
--> test.rs:6:33
|
6 | println!( "{:?}", i == j == k );
| ^ expected bool, found integer
|
Scala (here ">" is REPL)
> var i = 2
> var j = 2
> var k = 2
> i == j == k
^
warning: comparing values of types Boolean and Int
using `==` will always yield false
res0: Boolean = false
Kotlin
> var i = 2
> var j = 2
> var k = 2
> i == j == k
error: operator '==' cannot be applied to 'Boolean' and 'Int'
i == j == k
Nim
var i = 2
var j = 2
var k = 2
echo( i == j == k )
=> Error: type mismatch: got <bool, int>
but expected one of:
proc `==`(x, y: bool): bool
first type mismatch at position: 2
required type for y: bool
but expression 'k' is of type: int
expression: i == j == k
Python
> i = 2
> j = 2
> k = 2
> i == j == k
True
Julia
> i = 2
> j = 2
> k = 2
> i == j == k
true
So, apart from Python and Julia (which are dynamically typed so might be a bit different thing), it seems that more lately developed statically typed languages tend to give a warning (or even an error) against the use of i == j == k. So, if Python users may be likely to use Chapel, I guess it might be helpful (for the user) to give some warning (or even an error?) message.

Related

How to make the difference between the values of an array as minimal as possible?

Given an array A of integers N, and after inputting the integers into the array, I need to make the difference between the neighboring less or equal to D and we need to do that in minimal moves. In the end print out the sum of the numbers that have been added or subtracted.
For every 0 < i < N, |S[i] - S[i - 1]| <= D
You can increase and decrease the number of the array element
Example 1: If we have an array like this
N = 7, D = 3 [2, 10, 2, 6, 4, 3, 3], then in this array we have to make the difference between the neighboring elements less or equal than 3. We don't modify the first array element, we skip over to the second array elements where we modify it from 10 down to 5 (since A[0] + 3 = 5), then we don't change the third element, we change the fourth element from 6 down to 5 (because A[3] + 3 = 5) and we don't change the rest of the elements because the difference between them is less than D. In the end we have to print out 6 (s = 0; 10 -> 5, s = 5; 6 -> 5, s = 6)
Example 2: If we have an array like this
N = 7, D = 0 [1, 4, 1, 2, 4, 2, 2]. Since D in this case is 0, by some logic we have to make all of the numbers the same. The most optimal (and in the fewest steps to solve this) way is we start with the last elements, we leave A[6] and A[5], we skip over to A[4]. Since A[4] is 4 and A[5] is 2, we have to change the 4 down to 2. Now since A[4] is 2, we skip over A[3] and we go to A[3] we change it from 1 up to 2. Then we change A[1] from 4 down to 2 and in the end, we change A[0] from 1 up to 2. In the end we have to print out 6 (s = 0; 4 -> 2, s = 2; 1 -> 2, s = 3; 4 -> 2, s = 5; 1 -> 2, s = 6).
Some other test cases:
N = 7, D = 1 [2, 10, 0, 2, 4, 3, 3] Solution: 10
N = 5, D = 1 [6, 5, 4, 3, 2] Solution: 0
I am unable to find an algorithm or an approach to this problem. I have tried several solutions and the closest I have come to solving it was 7/30 test cases.
My code:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
int n, d, s1 = 0, s2 = 1;
cin >> n >> d;
int a[n], b[n];
for(int i = 0; i < n; i++) {
cin >> a[i];
b[i] = a[i];
}
reverse(b, b + n);
for(int i = 1; i < n; i++) {
if(a[i] - a[i - 1] <= d) {
continue;
} else {
if(a[i] > a[i - 1] + d) {
while(a[i] > a[i - 1] + d) {
a[i]--;
s1++;
}
} else if(a[i - 1] - d > a[i]) {
while(a[i - 1] - d > a[i]) {
a[i]++;
s1++;
}
}
}
}
for(int i = 1; i < n; i++) {
if(b[i] - b[i - 1] <= d) {
continue;
} else {
if(b[i] > b[i - 1] + d) {
while(b[i] > b[i - 1] + d) {
b[i]--;
s2++;
}
} else if(b[i - 1] - d > b[i]) {
while(b[i - 1] - d > b[i]) {
b[i]++;
s2++;
}
}
}
}
if(s1 >= s2)
cout << s2;
else
cout << s1;
return 0;
}

Linear index for a diagonal run of an upper triangular matrix

Given a NxN matrix, I would like to linearly index into its upper right triangle,
following a diagonal by diagonal pattern, starting after the main diagonal.
For example, given a 4x4 matrix
X 0 3 5
X X 1 4
X X X 2
X X X X
I'm looking for a non recursive (closed form) function mapping linear indices from 0 to 5 to (x,y) achieving
f(0) = (0, 1)
f(1) = (1, 2)
f(2) = (2, 3)
f(3) = (0, 2)
f(4) = (1, 3)
f(5) = (0, 3)
Related for row by row runs:
Linear index upper triangular matrix
algorithm for index numbers of triangular matrix coefficients
Thanks to #loopy-walt's observation, we have an answer!
Using the result from Linear index upper triangular matrix, a transformation of the result
(i, j) |-> (j-i-1, j)
Gives the expected outcome.
Here is a C++ implementation.
#include<tuple>
#include<cmath>
// Linear indexing of the upper triangle, row by row
std::tuple<size_t, size_t> k2ij(size_t n, size_t k){
size_t i = n - 2 - (size_t)std::floor(std::sqrt(4*n*(n-1) - (8*k) -7)/2.0 - 0.5);
size_t j = k + i + 1 - n*(n-1)/2 + (n-i)*((n-i)-1)/2;
return {i,j};
}
// Linear indexing of the upper triangle, diagonal by diagonal
std::tuple<size_t, size_t> d2ij(size_t n, size_t d){
const auto [i, j] = k2ij(n, d);
return {j-i-1, j}; // Conversion from row by row to diag by diag
}
#include<iostream>
#include<set>
int main(int argc, char** argv) {
size_t n = 4;
size_t top = n*(n-1)/2;
for(size_t d=0; d<top; ++d){
const auto [i,j] = d2ij(n, d);
std::cout << "d2ij(" << n << ", " << d << ") = (" << i << ", " << j << ")" << std::endl;
}
return 0;
}
Producing
d2ij(4, 0) = (0, 1)
d2ij(4, 1) = (1, 2)
d2ij(4, 2) = (2, 3)
d2ij(4, 3) = (0, 2)
d2ij(4, 4) = (1, 3)
d2ij(4, 5) = (0, 3)
Note: if someone wishes the form f(d) instead, a lambda can be used to capture the dimension 'n'
auto f = [n](size_t d){return d2ij(n, d);};
const auto [i,j] = f(5);
Thanks to everybody that took the time to read and help!
I created a custom method for the array and value you gave.
int a[4][4] ={{-1, 0, 3, 5}, {-1, -1, 1, 4}, {-1, -1, -1, 2}, {-1, -1, -1, -1}};
The code is exactly like this. You give the array And whatever you give to the second value in the Func method, the indexes of the value in the upper diagonal will reach you.
#include <iostream>
using namespace std;
int b[2] ={-1,-1};
int Func(int a[4][4],int n)
{
for(int i =0;i<4;i++)
{
for(int j=0;j<4;j++)
{
if(a[i][j]==n)
{
if(i<j)
{
b[0]=i;
b[1]=j;
return 0;
}
}
}
}
}
int main()
{
int a[4][4] ={{-1, 0, 3, 5}, {-1, -1, 1, 4}, {-1, -1, -1, 2}, {-1, -1, -1, -1}};
Func(a,5);
for(int i=0;i<2;i++)
{
cout<<b[i]<<" ";
}
return 0;
}
thank you USEFUL for feedback if it worked for you
Maybe someone can come up with a math formula that doesn't require a loop, but until then I've come up with a O(N) solution:
#include <utility>
constexpr std::pair<int, int> f(int n, int idx)
{
int group_size = n - 1;
int rest = idx + 1;
while (rest > group_size)
{
rest = rest - group_size;
--group_size;
}
return {(rest - 1) % group_size,
n - group_size + (rest - 1) % group_size};
}
/* 3x3
X 0 2
X X 1
X X X
*/
static_assert(f(3, 0) == std::pair{0, 1});
static_assert(f(3, 1) == std::pair{1, 2});
static_assert(f(3, 2) == std::pair{0, 2});
// 4x4
static_assert(f(4, 0) == std::pair{0, 1});
static_assert(f(4, 1) == std::pair{1, 2});
static_assert(f(4, 2) == std::pair{2, 3});
static_assert(f(4, 3) == std::pair{0, 2});
static_assert(f(4, 4) == std::pair{1, 3});
static_assert(f(4, 5) == std::pair{0, 3});
/* 5x5
X 0 4 7 9
X X 1 5 8
X X X 2 6
X X X X 3
X X X X X
*/
static_assert(f(5, 0) == std::pair{0, 1});
static_assert(f(5, 1) == std::pair{1, 2});
static_assert(f(5, 2) == std::pair{2, 3});
static_assert(f(5, 3) == std::pair{3, 4});
static_assert(f(5, 4) == std::pair{0, 2});
static_assert(f(5, 5) == std::pair{1, 3});
static_assert(f(5, 6) == std::pair{2, 4});
static_assert(f(5, 7) == std::pair{0, 3});
static_assert(f(5, 8) == std::pair{1, 4});
static_assert(f(5, 9) == std::pair{0, 4});
So you want the inverse of the following function
Zero-based indexing form of element [i,j] for a n×n upper triangular matrix including the diagonal
index = i*n-i*(i+1)/2+j
i=0..4, j=0..4, index=
| 0 | 1 | 2 | 3 | 4 |
| X | 5 | 6 | 7 | 8 |
| X | X | 9 | 10 | 11 |
| X | X | X | 12 | 13 |
| X | X | X | X | 14 |
The easiest algorithm I can think of is to loop for all rows i and see if there is a match for the column j such that:
i <= j
j>=0
j<n
Here is a sample code given index and n
for(i=0; i<n; i++)
{
j = index - i*n + i*(i+1)/2
if( j>=0 && j<n && j>= i)
{
break;
}
}
And example with n=7 and [i,j]=[1,5] produces index=11. Now the coordinates of this index are
i
j
i<=j && j>=0 && j<7
0
11
1
5
valid
2
0
3
-4
4
-7
5
-9
6
-10
If you want strictly the upper triangular elements, excluding the diagonal then
Zero-based indexing form of element [i,j] for a n×n upper triangular matrix excluding the diagonal
index = i*n-i*(i+3)/2+j-1
i=0..3, j=0..4, index=
| X | 0 | 1 | 2 | 3 |
| X | X | 4 | 5 | 6 |
| X | X | X | 7 | 8 |
| X | X | X | X | 9 |
| X | X | X | X | X |
The algorithm now is to loop for all rows i and see if there is a match for the column j such that:
i < j
j>0
j<n
Here is a sample code given index and n
for(i=0; i<n; i++)
{
j = index - i*n + i*(i+3)/2 + 1
if( j>0 && j<n && j>i)
{
break;
}
}
And example with n=7 and [i,j]=[1,5] produces index=9. Now the coordinates of this index are
i
j
i<j && j>0 && j<7
0
10
1
5
valid
2
1
3
-2
4
-4
5
-5

Count All Sub sequences having Product less than K

Given a non-negative array, find the number of subsequences having a product smaller than K.
Examples:
Input : [1, 2, 3, 4]
k = 10
Output :11
Input : [4, 8, 7, 2]
k = 50
Output : 9
So, We want to count the number of subsequences whose product is less than K.
There are sub-problems, and it can be solved using Dynamic Programming
However, I tried to write down the recursive code for better understanding.
Note: I am getting an answer as 6, which is wrong.
Can someone help me, How to foresee the correct Logic?
#include <bits/stdc++.h>
using namespace std;
vector<int> A{1, 2, 3, 4};
int countSubsequence(int i, int prod, int K)
{
if(prod > 1 && prod <= K)
return 1;
if(i >= A.size() || prod > K)
return 0;
return countSubsequence(i + 1, prod, K) + countSubsequence(i + 1, prod*A[i], K);
}
int main()
{
int K = 10;
cout << countSubsequence(0, 1, K);
return 0;
}
The condition
if(prod > 1 && prod <= K)
return 1;
will have it return from the function (for example) when [1, 2] is selected from [1, 2, 3, 4] and prevent it from searching for [1, 2, 3].
Also:
The condition prod <= K is wrong becasue you want the product smaller than K, not K or smaller.
You cannot distinguish "nothing is multiplied" and "only the number 1 is multiplied" when you use 1 as the initial value.
Try this:
#include <bits/stdc++.h>
using namespace std;
vector<int> A{1, 2, 3, 4};
int countSubsequence(int i, int prod, int K)
{
if(i >= A.size() && 0 <= prod && prod < K)
return 1;
if(i >= A.size() || prod >= K)
return 0;
return countSubsequence(i + 1, prod, K) + countSubsequence(i + 1, prod < 0 ? A[i] : prod*A[i], K);
}
int main()
{
int K = 10;
cout << countSubsequence(0, -1, K);
return 0;
}

Problem: Shortest path in a grid between multiple point with a constraint

Problem description:
I'm trying to solve a problem on the internet and I wasn't able to pass all testcases, well, because my logic is flawed and incorrect. The flaw: I assumed starting to the closest 'F' point will get me to the shortest paths always, at all cases.
Thinks I thought of:
Turning this into a graph problem and solve it based on it. > don't think this would work because of the constraint?
Try to obtain all possible solution combinations > does not scale, if !8 combination exist.
#include <iostream>
#include <utility>
#include <string>
#include <vector>
#include <queue>
using namespace std;
#define N 4
#define M 4
int SearchingChallenge(string strArr[], int arrLength) {
int n = arrLength, m = n, steps = 0, food = 0;
// initial position of charlie
int init_j = 0;
int init_i = 0;
queue<pair<int,int>> q;
// directions
vector<int> offsets = {0,-1,0,1,0};
vector<pair<int,int>> food_nodes;
//store visited nodes, no need for extra work to be done.
int visited_nodes[4][4] = {{0}};
// get number of food pieces
for(int i = 0; i < m; i++){
for(int j = 0; j < n ; j++){
if(strArr[i][j] == 'F')
{
food++;
}
if(strArr[i][j] == 'C')
{
strArr[i][j] = 'O';
food_nodes.push_back({i,j});
}
}
}
while(food_nodes.size()>0){
food_nodes.erase(food_nodes.begin());
int break_flag=0;
q.push(food_nodes[0]);
while(!q.empty()){
int size = q.size();
while(size-->0){
pair<int,int> p = q.front();
q.pop();
for(int k = 0; k < 4; k++){
int ii = p.first + offsets[k], jj = p.second + offsets[k+1];
/* if(ii == 0 && jj == 3)
printf("HI"); */
if(jj >= 0 && jj < 4 && ii < 4 && ii >=0){
if(strArr[ii][jj] == 'F'){
strArr[ii][jj] = 'O';
while(!q.empty())
q.pop();
break_flag=1;
food--;
food_nodes.push_back({ii,jj});
break;
}
if(strArr[ii][jj] == 'O')
q.push({ii,jj});
if(strArr[ii][jj] == 'H' && food == 0)
return ++steps;
}
}
if(break_flag==1)
break;
}
steps++;
if(break_flag==1)
break;
}
}
return 0;
}
int main(void) {
// keep this function call here
/* Note: In C++ you first have to initialize an array and set
it equal to the stdin to test your code with arrays. */
//passing testcase
//string A[4] = {"OOOO", "OOFF", "OCHO", "OFOO"};
//failing testcase
string A[4] = {"FOOF", "OCOO", "OOOH", "FOOO"}
int arrLength = sizeof(A) / sizeof(*A);
cout << SearchingChallenge(A, arrLength);
return 0;
}
Your help is appreciated.
I have wrote the javascript solution for the mentioned problem..
function SearchingChallenge(strArr) {
// create coordinate array
const matrix = [
[0, 0], [0, 1], [0, 2], [0, 3],
[1, 0], [1, 1], [1, 2], [1, 3],
[2, 0], [2, 1], [2, 2], [2, 3],
[3, 0], [3, 1], [3, 2], [3, 3]
]
// flatten the strArr
const flattenArray = flatten(strArr)
// segreagate and map flattenArray with matrix to get coordinate of food,charlie and home
const segregatedCoordinates = flattenArray.reduce((obj, char, index) => {
if (char === 'F') obj['food'].push(matrix[index])
else if (char === 'C') obj['dog'] = matrix[index]
else if (char === 'H') obj['home'] = matrix[index]
return obj
}, { "food": [], dog: null, home: null })
// construct possible routes by permutating food coordinates
let possibleRoutes = permuate(segregatedCoordinates['food'])
// push dog and home in possibleRoutes at start and end positions
possibleRoutes = possibleRoutes.map((route) => {
return [segregatedCoordinates['dog'], ...route, segregatedCoordinates['home']]
})
// Calculate distances from every possible route
const distances = possibleRoutes.reduce((distances, route) => {
let moveLength = 0
for (let i = 0; i < route.length - 1; i++) {
let current = route[i], next = route[i + 1]
let xCoordinatePath = current[0] > next[0] ? (current[0] - next[0]) : (next[0] - current[0])
let yCoordinatePath = current[1] > next[1] ? (current[1] - next[1]) : (next[1] - current[1])
moveLength += xCoordinatePath + yCoordinatePath
}
distances.push(moveLength)
return distances
}, [])
return Math.min(...distances);
}
function permuate(arr) {
if (arr.length <= 2) return (arr.length === 2 ? [arr, [arr[1], arr[0]]] : arr)
return arr.reduce((res, ele, index) => {
res = [...res, ...permuate([...arr.slice(0, index), ...arr.slice(index + 1)]).map(val => [ele, ...val])]
return res
}, [])
}
function flatten(inputtedArr) {
return inputtedArr.reduce((arr, row) => {
arr = [...arr, ...row]
return arr
}, [])
}
console.log(SearchingChallenge(['FOOF', 'OCOO', 'OOOH', 'FOOO']));
You can write a DP solution where you have a 4x4x8 grid. The first two axis represent the x and y coordinate. The third one represent the binary encoding of which food item you picked already.
Each cell in the grid stores the best number of moves to get at this cell having eaten the specified foods. So for example, grid[2][2][2] is the cost of getting to cell (2,2) after having eaten the second piece of food only.
Then you set the value of the start cell, at third index 0 to 0, all the other cells to -1. You keep a list of the cells to propagate (sorted by least cost), and you add the start cell to it.
Then you repeatedly take the next cell to propagate, remove it and push the neighboring cell with cost +1 and updated food consume. Once you reach the destination cell with all food consumed, you're done.
That should take no more than 4x4x8 updates, with about the same order of priority queue insertion. O(n log(n)) where n is xy2^f. As long as you have few food items this will be almost instant.
C++ solution
I used both dfs and bfs for this problem
TIME COMPLEXITY - (4^(N×M))+NO_OF_FOODS×N×M
#include <bits/stdc++.h>
using namespace std;
//It is a dfs function it will find and store all the possible steps to eat all food in toHome map
void distAfterEatingAllFood(vector<vector<char>> &m, int countOfFood, int i, int j, int steps, map<pair<int,int>,int>&toHome){
if(i<0 || j<0 || i>=4 || j>=4 || m[i][j]=='*') return;
if(m[i][j]=='F') countOfFood--;
if(countOfFood==0){
if(!toHome.count({i,j}))
toHome[{i,j}] = steps;
else if(toHome[{i,j}]>steps)
toHome[{i,j}] = steps;
return;
}
char temp = m[i][j];
m[i][j] = '*';
distAfterEatingAllFood(m, countOfFood, i+1, j, steps+1, toHome);
distAfterEatingAllFood(m, countOfFood, i-1, j, steps+1, toHome);
distAfterEatingAllFood(m, countOfFood, i, j+1, steps+1, toHome);
distAfterEatingAllFood(m, countOfFood, i, j-1, steps+1, toHome);
m[i][j] = temp;
return;
}
//It is a bfs function it will iterate over the toHome map and find the shortest distance between the last food position to home
int lastFoodToHome(vector<vector<char>> &m, int i, int j, int steps){
queue<pair<pair<int, int>,int>>q;
vector<vector<int>> vis(4, vector<int>(4, 0));
q.push({{i, j}, steps});
vis[i][j] = 1;
int dirX[] = {0, 1, 0, -1};
int dirY[] = {1, 0, -1, 0};
while (!q.empty())
{
int x = q.front().first.first;
int y = q.front().first.second;
int steps = q.front().second;
q.pop();
if (m[x][y] == 'H')
return steps;
for (int k = 0; k < 4; k++)
{
int ni = x + dirX[k];
int nj = y + dirY[k];
if (ni >= 0 && nj >= 0 && ni < 4 && nj < 4 && !vis[ni][nj])
{
if(m[ni][nj] == 'H') return steps + 1;
q.push({{ni, nj}, steps + 1});
vis[i][j] = 1;
}
}
}
return INT_MAX;
}
int main()
{
vector<vector<char>> m(4, vector<char>(4));
int countOfFood = 0, x, y;
for (int i = 0; i < 4; i++){
for (int j = 0; j < 4; j++){
cin >> m[i][j];
if (m[i][j] == 'C'){
x = i;
y = j;
}
if (m[i][j] == 'F')
countOfFood++;
}
}
map<pair<int,int>,int>toHome;
distAfterEatingAllFood(m, countOfFood, x, y, 0, toHome);
int ans = INT_MAX;
for(auto &i:toHome){
ans = min(ans, lastFoodToHome(m, i.first.first, i.first.second, i.second));
}
cout<<ans;
return 0;
}

How to count connected cells in a grid?

I'm trying to solve the Hackerrank problem "Connected Cells in a Grid". The task is to find the largest region (connected cells consisting of ones) in the grid.
My approach was to add the number of ones I find only if the element hasn't been visited yet, then I take the maximum of several paths. It doesn't seem to be working for the following test case:
5
5
1 1 0 0 0
0 1 1 0 0
0 0 1 0 1
1 0 0 0 1
0 1 0 1 1
Is there something wrong with my approach?
#include <vector>
#include <algorithm>
using namespace std;
#define MAX 10
bool visited[MAX][MAX];
int maxRegion(vector<vector<int>> const& mat, int i, int j) {
int result;
if ((i == 0 && j == 0) || visited[i][j]) {
result = 0;
}
else if (i == 0) {
result = mat[i][j-1] + maxRegion(mat, i, j-1);
}
else if (j == 0) {
result = mat[i-1][j] + maxRegion(mat, i-1, j);
}
else {
result = mat[i-1][j-1] +
max({maxRegion(mat, i-1, j),
maxRegion(mat, i, j-1),
maxRegion(mat, i-1, j-1)});
}
visited[i][j] = true;
return result;
}
I think it's very natural to formulate this program as a connected components problem. Specifically, I've used boost::graph for this.
The idea is to build a graph whose each entry in the matrix is a node, and there are edges between horizontal and vertical 1 entries. Once such a graph is built, all that is needed is to run the connected components algorithm, and find the biggest component.
The following code does so:
#include <iostream>
#include <vector>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/connected_components.hpp>
using namespace std;
using namespace boost;
int main()
{
vector<vector<int>> v{{1, 1, 0, 0, 0}, {0, 1, 1, 0, 0}, {0, 0, 1, 0, 1}, {1, 0, 0, 0, 1}, {0, 1, 0, 1, 1}};
typedef adjacency_list <vecS, vecS, undirectedS> graph;
graph g(v.size() * v.size());
// Populate the graph edges
for(size_t i = 0; i < v.size() - 1; ++i)
for(size_t j = 0; j < v[i].size() - 1; ++j)
{
if(v[i][j] == 1 && v[i + 1][j] == 1)
add_edge(i * v.size() + j, (i + 1) * v.size() + j, g);
else if(v[i][j] == 1 && v[i][j + 1] == 1)
add_edge(i * v.size() + j, i * v.size() + j + 1, g);
}
// Run the connected-components algorithm.
vector<int> component(num_vertices(g));
int num = connected_components(g, &component[0]);
// Print out the results.
std::vector<int>::size_type i;
for(i = 0; i != component.size(); ++i)
cout << "Vertex (" << i / v.size() << ", " << i % v.size() << ") is in component " << component[i] << endl;
cout << endl;
}
The output is
Vertex (0, 0) is in component 0
Vertex (0, 1) is in component 0
Vertex (0, 2) is in component 1
Vertex (0, 3) is in component 2
Vertex (0, 4) is in component 3
Vertex (1, 0) is in component 4
Vertex (1, 1) is in component 0
Vertex (1, 2) is in component 0
Vertex (1, 3) is in component 5
Vertex (1, 4) is in component 6
Vertex (2, 0) is in component 7
Vertex (2, 1) is in component 8
Vertex (2, 2) is in component 0
Vertex (2, 3) is in component 9
Vertex (2, 4) is in component 10
Vertex (3, 0) is in component 11
Vertex (3, 1) is in component 12
Vertex (3, 2) is in component 13
Vertex (3, 3) is in component 14
Vertex (3, 4) is in component 15
Vertex (4, 0) is in component 16
Vertex (4, 1) is in component 17
Vertex (4, 2) is in component 18
Vertex (4, 3) is in component 19
Vertex (4, 4) is in component 20
Note that the program encodes i, j (for the case where the dimension is 5) by 5 i + j. This is easily invertible.
You can represent the matrix as an undirected graph and use DFS or BFS to find the connected component with the most nodes: every cell containing 1 can become a node, and there is an edge between two nodes if the corresponding cells are adjacent.
If you still need some guidance with the solution, here is mine in Python - passed all tests :) (visit my github to see other challenges that I've solved there in C++ as well)
def getBiggestRegion(grid, n, m):
max_region = 0
region_size = 0
for i in xrange(n):
for j in xrange(m):
if grid[i][j] == 1:
region_size = mark_region(grid, i, j, n, m)
#region_size += 1
if region_size > max_region:
max_region = region_size
return max_region
def push_if_valid(stack, i, j, n, m):
if 0 <= i < n and 0 <= j < m:
stack.append((i, j))
dirs = [[1,0], [0,1], [-1,0], [0,-1], [-1,-1], [-1, 1], [1,1], [1, -1]]
def mark_region(grid, i, j, n, m):
stack = []
stack.append((i, j))
region_size = 0
while stack:
curr = stack.pop()
ci = curr[0]
cj = curr[1]
if grid[ci][cj] == 1:
grid[ci][cj] = 2
region_size += 1
#this for loop is for going in all the directions
#North, South, East, West, NW, SW, SE, NE
#in my C++ Pacman sol, I have the actual lines instead
for dir in dirs:
push_if_valid(stack, ci + dir[0], cj + dir[1], n, m)
return region_size
n = int(raw_input().strip())
m = int(raw_input().strip())
grid = []
for grid_i in xrange(n):
grid_t = list(map(int, raw_input().strip().split(' ')))
grid.append(grid_t)
print(getBiggestRegion(grid, n, m))