I have a basic implementation of hole-filling filter as shown below:
#include <iostream>
#include <opencv2/opencv.hpp>
int main(int argc, char** argv)
{
// please note that the depthImg is (720 x 576) 8UC1
// let's make a smaller one for testing
uchar flatten[6 * 8] = { 140, 185, 48, 235, 201, 192, 131, 57,
55, 87, 82, 0, 6, 201, 0, 38,
6, 239, 82, 142, 46, 33, 172, 72,
133, 0, 232, 226, 66, 59, 10, 204,
214, 123, 202, 100, 0, 32, 6, 147,
105, 191, 50, 21, 87, 117, 118, 244};
cv::Mat depthImg = cv::Mat(6, 8, CV_8UC1, flatten);
// please ignore the border pixels in this case
for (int i = 1; i < depthImg.cols - 1; i++) {
for (int j = 1; j < depthImg.rows - 1; j++) {
unsigned short sumNonZeroAdjs = 0;
uchar countNonZeroAdjs = 0;
if (depthImg.at<uchar>(j, i) == 0) {
uchar iMinus1 = depthImg.at<uchar>(j, i - 1);
uchar iPlus1 = depthImg.at<uchar>(j, i + 1);
uchar jMinus1 = depthImg.at<uchar>(j - 1, i);
uchar jPlus1 = depthImg.at<uchar>(j + 1, i);
if (iMinus1 != 0) {
sumNonZeroAdjs += iMinus1;
countNonZeroAdjs++;
}
if (iPlus1 != 0) {
sumNonZeroAdjs += iPlus1;
countNonZeroAdjs++;
}
if (jMinus1 != 0) {
sumNonZeroAdjs += jMinus1;
countNonZeroAdjs++;
}
if (jPlus1 != 0) {
sumNonZeroAdjs += jPlus1;
countNonZeroAdjs++;
}
depthImg.at<uchar>(j, i) = sumNonZeroAdjs / countNonZeroAdjs;
}
}
}
std::cout << depthImg << std::endl;
return 0;
}
// prints the following:
[140, 185, 48, 235, 201, 192, 131, 57;
55, 87, 82, 116, 6, 201, 135, 38;
6, 239, 82, 142, 46, 33, 172, 72;
133, 181, 232, 226, 66, 59, 10, 204;
214, 123, 202, 100, 71, 32, 6, 147;
105, 191, 50, 21, 87, 117, 118, 244]
The above filter computes an average of adjacent pixels to fill the 0 pixels. The output from this implementation is satisfactory. However, as we can see, the above prototype is not elegant and painfully slow.
I am looking for a similar logic (using adjacent pixels to fill 0 pixels) but faster (execution time) hole-filling filter inbuilt in OpenCV
PS: I am using OpenCV v4.2.0 on Ubuntu 20.04 LTS.
Update 1
Based on the suggestions, I designed pointer style access. Complete code is shown below:
#include <iostream>
#include <opencv2/opencv.hpp>
void inPlaceHoleFillingExceptBorderPtrStyle(cv::Mat& img) {
typedef uchar T;
T* ptr = img.data;
size_t elemStep = img.step / sizeof(T);
for (int i = 1; i < img.rows - 1; i++) {
for (int j = 1; j < img.cols - 1; j++) {
T& curr = ptr[i * elemStep + j];
if (curr != 0) {
continue;
}
ushort sumNonZeroAdjs = 0;
uchar countNonZeroAdjs = 0;
T iM1 = ptr[(i - 1) * elemStep + j];
T iP1 = ptr[(i + 1) * elemStep + j];
T jM1 = ptr[i * elemStep + (j - 1)];
T jP1 = ptr[i * elemStep + (j + 1)];
if (iM1 != 0) {
sumNonZeroAdjs += iM1;
countNonZeroAdjs++;
}
if (iP1 != 0) {
sumNonZeroAdjs += iP1;
countNonZeroAdjs++;
}
if (jM1 != 0) {
sumNonZeroAdjs += jM1;
countNonZeroAdjs++;
}
if (jP1 != 0) {
sumNonZeroAdjs += jP1;
countNonZeroAdjs++;
}
if (countNonZeroAdjs > 0) {
curr = sumNonZeroAdjs / countNonZeroAdjs;
}
}
}
}
void inPlaceHoleFillingExceptBorder(cv::Mat& img) {
typedef uchar T;
for (int i = 1; i < img.cols - 1; i++) {
for (int j = 1; j < img.rows - 1; j++) {
ushort sumNonZeroAdjs = 0;
uchar countNonZeroAdjs = 0;
if (img.at<T>(j, i) != 0) {
continue;
}
T iM1 = img.at<T>(j, i - 1);
T iP1 = img.at<T>(j, i + 1);
T jM1 = img.at<T>(j - 1, i);
T jP1 = img.at<T>(j + 1, i);
if (iM1 != 0) {
sumNonZeroAdjs += iM1;
countNonZeroAdjs++;
}
if (iP1 != 0) {
sumNonZeroAdjs += iP1;
countNonZeroAdjs++;
}
if (jM1 != 0) {
sumNonZeroAdjs += jM1;
countNonZeroAdjs++;
}
if (jP1 != 0) {
sumNonZeroAdjs += jP1;
countNonZeroAdjs++;
}
if (countNonZeroAdjs > 0) {
img.at<T>(j, i) = sumNonZeroAdjs / countNonZeroAdjs;
}
}
}
}
int main(int argc, char** argv) {
// please note that the img is (720 x 576) 8UC1
// let's make a smaller one for testing
// clang-format off
uchar flatten[6 * 8] = { 140, 185, 48, 235, 201, 192, 131, 57,
55, 87, 82, 0, 6, 201, 0, 38,
6, 239, 82, 142, 46, 33, 172, 72,
133, 0, 232, 226, 66, 59, 10, 204,
214, 123, 202, 100, 0, 32, 6, 147,
105, 191, 50, 21, 87, 117, 118, 244};
// clang-format on
cv::Mat img = cv::Mat(6, 8, CV_8UC1, flatten);
cv::Mat img1 = img.clone();
cv::Mat img2 = img.clone();
inPlaceHoleFillingExceptBorderPtrStyle(img1);
inPlaceHoleFillingExceptBorder(img2);
return 0;
}
/*** expected output
[140, 185, 48, 235, 201, 192, 131, 57;
55, 87, 82, 116, 6, 201, 135, 38;
6, 239, 82, 142, 46, 33, 172, 72;
133, 181, 232, 226, 66, 59, 10, 204;
214, 123, 202, 100, 71, 32, 6, 147;
105, 191, 50, 21, 87, 117, 118, 244]
***/
Update 2
Based on the suggestion, the point style code is further improved as shown below:
void inPlaceHoleFillingExceptBorderImpv(cv::Mat& img) {
typedef uchar T;
size_t elemStep = img.step1();
const size_t margin = 1;
for (size_t i = margin; i < img.rows - margin; ++i) {
T* ptr = img.data + i * elemStep;
for (size_t j = margin; j < img.cols - margin; ++j, ++ptr) {
T& curr = ptr[margin];
if (curr != 0) {
continue;
}
T& north = ptr[margin - elemStep];
T& south = ptr[margin + elemStep];
T& east = ptr[margin + 1];
T& west = ptr[margin - 1];
ushort sumNonZeroAdjs = 0;
uchar countNonZeroAdjs = 0;
if (north != 0) {
sumNonZeroAdjs += north;
countNonZeroAdjs++;
}
if (south != 0) {
sumNonZeroAdjs += south;
countNonZeroAdjs++;
}
if (east != 0) {
sumNonZeroAdjs += east;
countNonZeroAdjs++;
}
if (west != 0) {
sumNonZeroAdjs += west;
countNonZeroAdjs++;
}
if (countNonZeroAdjs > 0) {
curr = sumNonZeroAdjs / countNonZeroAdjs;
}
}
}
}
There are three parts: 1) find the zeros, 2) find the mean, and 3) fill the found zeros with mean. So:
/****
* in-place fill zeros with the mean of the surrounding neighborhoods
***/
void fillHoles(Mat gray){
// find the zeros
Mat mask = (gray == 0);
// find the mean with filter2d
Mat kernel = (Mat_<double>(3,3) <<
1/8, 1/8, 1/8
1/8, 0 , 1/8
1/8, 1/8, 1/8
);
Mat avg;
cv::filter2d(gray, avg, CV_8U, kernel)
// then fill the zeros, only where indicated by `mask`
cv::bitwise_or(gray, avg, gray, mask);
}
Note I just realize that this is plainly taking the average, not the non-zero average. For that operation, you might want to do two filters, one for the sum, one for the non-zero counts, then divide the two:
// find the neighborhood sum with filter2d
Mat kernel = (Mat_<double>(3,3) <<
1, 1, 1
1, 0, 1
1, 1, 1
);
Mat sums;
cv::filter2d(gray, sums, CV_64F, kernel);
// find the neighborhood count with filter2d
Mat counts;
cv::filter2d(gray!=0, counts, CV_64F, kernel);
counts /= 255; // because gray!=0 returns 255 where true
// force counts to 1 if 0, so we can divide later
cv::max(counts, 1, counts);
Mat out;
cv::divide(sums, counts, out);
out.convertTo(gray, CV_8U);
#QuangHoang advised a fantastic kernel-based approach. Unfortunately, the result is not matching with the expected output.
Therefore, based on various comments from #CrisLuengo, I managed to design time efficient version of the filter, as shown below:
void inPlaceHoleFillingExceptBorderFast(cv::Mat& img) {
typedef uchar T;
const size_t elemStep = img.step1();
const size_t margin = 1;
for (size_t i = margin; i < img.rows - margin; ++i) {
T* ptr = img.data + i * elemStep;
for (size_t j = margin; j < img.cols - margin; ++j, ++ptr) {
T& curr = ptr[margin];
if (curr != 0) {
continue;
}
T& east = ptr[margin + 1];
T& west = ptr[margin - 1];
T& north = ptr[margin - elemStep];
T& south = ptr[margin + elemStep];
// convert to 0/1 and sum them up
uchar count = static_cast<bool>(north) + static_cast<bool>(south) +
static_cast<bool>(east) + static_cast<bool>(west);
// we do not want to divide by 0
if (count > 0) {
curr = (north + south + east + west) / count;
}
}
}
}
I am trying to make a shell algorithm to arrange a [5][5][5] array, so far I can print the whole array but when I run shell() it prints the same array. It doesn't print the numbers arranged. Any help please?
#include <iostream>
#include <stdlib.h>
using namespace std;
void ordShell(int numbers[5][5][5], int n);
void exchange(int& x, int& y);
int main()
{
int numbers[5][5][5] = {
{ {1,2,3,4,5}, {41,42,43,44,45}, {11,12,13,14,15}, {16, 17, 18, 19, 20}, {21, 22, 23, 24, 25} },
{ {26,27,28,29,30}, {31,32,33,34,35 }, {36,37,38,39,40}, {6,7,8,9,10}, {46, 47, 48, 49, 50}, },
{ {51, 52, 53, 54, 55}, {56,57,58,59,60}, {61,62,63,64,65}, {66, 67, 68, 69, 70}, {71, 72, 73, 74, 75}, },
{ {76, 77, 78, 79, 80}, {81,82,83,84,85}, {86,87,88,89,90}, {91, 92, 93, 94, 95}, {96, 97, 98, 99, 100}, },
{ {101, 102, 103, 104, 105}, {106,107,108,109,110}, {111, 112, 113, 114, 115}, {116, 117, 118, 119, 120}, {121, 122, 123, 124, 125} }
};
for(int i=0;i<5;i++)
{
for(int j=0;j<5;j++)
{
for(int l=0;l<5;l++)
{
cout<<numbers[i][j][l]<<",";
}
}}
cout<<"whatever"<<"";
cout<<"\n"<<"";
cout<<"NOW COMES SHELL"<<"";
ordShell(numbers,5);
cout<<"NUMBERS ARRANGED AFTER SHELL"<<"";
for(int i=0;i<5;i++)
{
for(int j=0;j<5;j++)
{
for(int l=0;l<5;l++)
{
cout<<numbers[i][j][l]<<",";
}
}}
return 0;
}
void ordShell(int numbers[5][5][5], int n)
{
int jump, i, j, k,j1,j2,k1,k2;
jump = n / 2;
while (jump > 0)
{
for (i = jump; i < n; i++)
{
j = i - jump;
j1= i - jump;
j2= i - jump;
while (j >= 0 )
{
k = j + jump;
k1 = j + jump;
k2 = j + jump;
if (numbers[j][j1][j2] <= numbers[k][k1][k2])
{j = -1; // arranged pair
j1 = -1;
j2 = -1;}
else
{
cout<<"exchange: "<<"";
cout<<numbers[j][j1][j2]<<" ";
cout<<numbers[k][k1][k2]<<"\n";
exchange(numbers[j][j1][j2], numbers[k][k1][k2]);
j -= jump;
j1 -= jump;
j2 -= jump;
}
}
}
jump = jump / 2;
cout<<"Jump: "<<jump<<"\n";
}
}
void exchange(int& x, int& y)
{
int aux = x;
x = y;
y = aux;
}
The problem is quite simple in your function: you aren't modifying the array but only a copy of it:
void ordShell(int numbers[5][5][5], int n)//makes a copy of numbers
If you want to avoid the issue, you need to give a pointer to your function instead.
However, the C++ way is to use the STL instead so you should make your array that way: std::vector<std::vector<std::vector<int> > > (you can use the same initialization after)
That way in your function you would only need to pass a reference to this:
void ordShell(std::vector<std::vector<std::vector<int> > >& numbers, int n)
You can also use typedef to make the variable name easier to read:
typedef std::vector<std::vector<std::vector<int> > > vector3D
And one last thing, you don't need your exchange function, std::swap does the same thing.
I am currently trying to allow the user to input values into a Sudoku solver however I keep getting an error. Here is the code:
#include <iostream> //
#include <fstream>
using namespace std;
class SudokuBoard;
void printB(SudokuBoard sb);
typedef unsigned int uint;
const uint MAXVAL = 9;
const uint L = 9;
const uint C = 9;
const uint S = L * C;
const uint ZONEL = 3;
const uint ZONEC = 3;
const uint ZONES = ZONEL * ZONEC;
const uint lineElements[L][C] = {
{ 0, 1, 2, 3, 4, 5, 6, 7, 8},
{ 9, 10, 11, 12, 13, 14, 15, 16, 17},
{18, 19, 20, 21, 22, 23, 24, 25, 26},
{27, 28, 29, 30, 31, 32, 33, 34, 35},
{36, 37, 38, 39, 40, 41, 42, 43, 44},
{45, 46, 47, 48, 49, 50, 51, 52, 53},
{54, 55, 56, 57, 58, 59, 60, 61, 62},
{63, 64, 65, 66, 67, 68, 69, 70, 71},
{72, 73, 74, 75, 76, 77, 78, 79, 80}
};
const uint columnElements[C][L] = {
{ 0, 9, 18, 27, 36, 45, 54, 63, 72},
{ 1, 10, 19, 28, 37, 46, 55, 64, 73},
{ 2, 11, 20, 29, 38, 47, 56, 65, 74},
{ 3, 12, 21, 30, 39, 48, 57, 66, 75},
{ 4, 13, 22, 31, 40, 49, 58, 67, 76},
{ 5, 14, 23, 32, 41, 50, 59, 68, 77},
{ 6, 15, 24, 33, 42, 51, 60, 69, 78},
{ 7, 16, 25, 34, 43, 52, 61, 70, 79},
{ 8, 17, 26, 35, 44, 53, 62, 71, 80}
};
const uint zoneElements[S / ZONES][ZONES] = {
{ 0, 1, 2, 9, 10, 11, 18, 19, 20},
{ 3, 4, 5, 12, 13, 14, 21, 22, 23},
{ 6, 7, 8, 15, 16, 17, 24, 25, 26},
{27, 28, 29, 36, 37, 38, 45, 46, 47},
{30, 31, 32, 39, 40, 41, 48, 49, 50},
{33, 34, 35, 42, 43, 44, 51, 52, 53},
{54, 55, 56, 63, 64, 65, 72, 73, 74},
{57, 58, 59, 66, 67, 68, 75, 76, 77},
{60, 61, 62, 69, 70, 71, 78, 79, 80}
};
class SudokuBoard {
public:
SudokuBoard() :
filledIn(0)
{
for (uint i(0); i < S; ++i)
table[i] = usedDigits[i] = 0;
}
virtual ~SudokuBoard() {
}
int const at(uint l, uint c) { // Returns the value at line l and row c
if (isValidPos(l, c))
return table[l * L + c];
else
return -1;
}
void set(uint l, uint c, uint val) { // Sets the cell at line l and row c to hold the value val
if (isValidPos(l, c) && ((0 < val) && (val <= MAXVAL))) {
if (table[l * C + c] == 0)
++filledIn;
table[l * C + c] = val;
for (uint i = 0; i < C; ++i) // Update lines
usedDigits[lineElements[l][i]] |= 1<<val;
for (uint i = 0; i < L; ++i) // Update columns
usedDigits[columnElements[c][i]] |= 1<<val;
int z = findZone(l * C + c);
for (uint i = 0; i < ZONES; ++i) // Update columns
usedDigits[zoneElements[z][i]] |= 1<<val;
}
}
void solve() {
try { // This is just a speed boost
scanAndSet(); // Logic approach
goBruteForce(); // Brute force approach
} catch (int e) { // This is just a speed boost
}
}
void scanAndSet() {
int b;
bool changed(true);
while (changed) {
changed = false;
for (uint i(0); i < S; ++i)
if (0 == table[i]) // Is there a digit already written?
if ((b = bitcount(usedDigits[i])) == MAXVAL - 1) { // If there's only one digit I can place in this cell, do
int d(1); // Find the digit
while ((usedDigits[i] & 1<<d) > 0)
++d;
set(i / C, i % C, d); // Fill it in
changed = true; // The board has been changed so this step must be rerun
} else if (bitcount(usedDigits[i]) == MAXVAL)
throw 666; // Speed boost
}
}
void goBruteForce() {
int max(-1); // Find the cell with the _minimum_ number of posibilities (i.e. the one with the largest number of /used/ digits)
for (uint i(0); i < S; ++i)
if (table[i] == 0) // Is there a digit already written?
if ((max == -1) || (bitcount(usedDigits[i]) > bitcount(usedDigits[max])))
max = i;
if (max != -1) {
for (uint i(1); i <= MAXVAL; ++i) // Go through each possible digit
if ((usedDigits[max] & 1<<i) == 0) { // If it can be placed in this cell, do
SudokuBoard temp(*this); // Create a new board
temp.set(max / C, max % C, i); // Complete the attempt
temp.solve(); // Solve it
if (temp.getFilledIn() == S) { // If the board was completely solved (i.e. the number of filled in cells is S)
for (uint j(0); j < S; ++j) // Copy the board into this one
set(j / C, j % C, temp.at(j / C, j % C));
return; // Break the recursive cascade
}
}
}
}
uint getFilledIn() {
return filledIn;
}
private:
uint table[S];
uint usedDigits[S];
uint filledIn;
bool const inline isValidPos(int l, int c) {
return ((0 <= l) && (l < (int)L) && (0 <= c) && (c < (int)C));
}
uint const inline findZone(uint off) {
return ((off / C / ZONEL) * (C / ZONEC) + (off % C / ZONEC));
}
uint const inline bitcount(uint x) {
uint count(0);
for (; x; ++count, x &= (x - 1));
return count;
}
};
void printB(SudokuBoard sb) {
cout << " ***** Sudoku Solver By Diego Freitas ***** " << endl;
cout << " | ------------------------------- |" << endl;
for (uint i(0); i < S; ++i) {
if (i % 3 == 0)
cout << " |";
cout << " " << sb.at(i / L, i % L);
if (i % C == C - 1) {
if (i / C % 3 == 2)
cout << " |" << endl << " | -------------------------------";
cout << " |" << endl;
}
}
cout << endl;
}
int main(int argc, char *argv[]) {
SudokuBoard sb;
ifstream fin("Sudoku.in");
int aux;
for (uint i(0); i < S; ++i) {
fin >> aux;
sb.set(i / L, i % L, aux);
}
fin.close();
printB(sb);
sb.solve();
printB(sb);
system ("PAUSE");
return 0;
}
If anyone has any alterations to the code then it will be appreciated. I am currently making this during my own time and I roughly want an idea how this works.
I've been learning to program for quite a bit and it seems that one of the greatest competitions between programmers is how few lines one can do a procedure in. Noticing this trend, I'd like to learn to make my programs a bit tighter, cleaner, and preferring functionality without excess. Here's the code I used to solve ProjectEuler problem 11. It's quite large which kinda worries me when I see code a fourth of its size doing the same thing, hehe.
#include <iostream>
using namespace std;
int array[20][20] = {{8,2,22,97,38,15,0,40,0,75,4,5,7,78,52,12,50,77,91,8},
{49,49,99,40,17,81,18,57,60,87,17,40,98,43,69,48,4,56,62,0},
{81,49,31,73,55,79,14,29,93,71,40,67,53,88,30,3,49,13,36,65},
{52,70,95,23,4,60,11,42,69,24,68,56,1,32,56,71,37,2,36,91},
{22,31,16,71,51,67,63,89,41,92,36,54,22,40,40,28,66,33,13,80},
{24,47,32,60,99,3,45,2,44,75,33,53,78,36,84,20,35,17,12,50},
{32,98,81,28,64,23,67,10,26,38,40,67,59,54,70,66,18,38,64,70},
{67,26,20,68,2,62,12,20,95,63,94,39,63,8,40,91,66,49,94,21},
{24,55,58,5,66,73,99,26,97,17,78,78,96,83,14,88,34,89,63,72},
{21,36,23,9,75,0,76,44,20,45,35,14,0,61,33,97,34,31,33,95},
{78,17,53,28,22,75,31,67,15,94,3,80,4,62,16,14,9,53,56,92},
{16,39,5,42,96,35,31,47,55,58,88,24,0,17,54,24,36,29,85,57},
{86,56,0,48,35,71,89,7,5,44,44,37,44,60,21,58,51,54,17,58},
{19,80,81,68,5,94,47,69,28,73,92,13,86,52,17,77,4,89,55,40},
{4,52,8,83,97,35,99,16,7,97,57,32,16,26,26,79,33,27,98,66},
{88,36,68,87,57,62,20,72,3,46,33,67,46,55,12,32,63,93,53,69},
{4,42,16,73,38,25,39,11,24,94,72,18,8,46,29,32,40,62,76,36},
{20,69,36,41,72,30,23,88,34,62,99,69,82,67,59,85,74,4,36,16},
{20,73,35,29,78,31,90,1,74,31,49,71,48,86,81,16,23,57,5,54},
{1,70,54,71,83,51,54,69,16,92,33,48,61,43,52,1,89,19,67,48},
};
int s = 0;
int right()
{
int a = 1;
int i = 0;
int n = 0;
int r = 0;
int c = 0;
for(n = 0;n <= 359;n++)
{
if(c <= 16)
{
for(i = 0;i <= 3;i++)
{
//cout << " " << array[r][(c + i)] << " ";
a *= array[r][(c + i)];
};
//cout << a << " ";
i = 0; c++;
if(a > s)
{
s = a;
a = 1;
};
//cout << s << " " << endl;
a = 1;
}else{c = 0; r++;};
};
return s;
};
int left()
{
int a = 1;
int i = 0;
int n = 0;
int r = 0;
int c = 19;
for(n = 0;n <= 359;n++)
{
if(c >= 3)
{
for(i = 0;i <= 3;i++)
{
//cout << " " << array[r][(c - i)] << " ";
a *= array[r][(c - i)];
};
//cout << a << " ";
i = 0; c--;
if(a > s)
{
s = a;
a = 1;
};
//cout << s << " " << endl;
a = 1;
}else{c = 19; r++;};
};
return s;
};
int down()
{
int n = 0;
int i = 0;
int r = 0;
int c = 0;
int a = 1;
for(n = 0;n <= 356;n++)
{
if(c <= 19)
{
for(i = 0;i <= 3;i++)
{
//cout << " " << array[(r + i)][c] << " ";
a *= array[(r + i)][c];
};
//cout << a << " ";
i = 0; c++;
if(a > s)
{
s = a;
a = 1;
};
//cout << s << " " << endl;
a = 1;
}else{c = 0;
if(r <= 16){
r++;
}else{break;};
};
};
return s;
};
int up()
{
int n = 0;
int i = 0;
int r = 19;
int c = 0;
int a = 1;
for(n = 0;n <= 356;n++)
{
if(c <= 19)
{
for(i = 0;i <= 3;i++)
{
//cout << " " << array[(r - i)][c] << " ";
a *= array[(r - i)][c];
};
//cout << a << " ";
i = 0; c++;
if(a > s)
{
s = a;
a = 1;
};
//cout << s << " " << endl;
a = 1;
}else{c = 0;
if(r >= 3){
r--;
}else{break;};
};
};
return s;
};
int diag_left_up()
{
int n = 0;
int i = 0;
int r = 19;
int c = 19;
int a = 1;
for(n = 0;n <= 304;n++)
{
if(c >= 3 && r >= 3)
{
for(i = 0;i <= 3;i++)
{
//cout << " " << array[(r - i)][(c - i)] << " ";
a *= array[(r - i)][(c - i)];
};
//cout << a << " ";
i = 0; c--;
if(a > s)
{
s = a;
a = 1;
};
//cout << s << " " << endl;
a = 1;
}else{c = 19;
if(r >= 3){
r--;
}else{break;};
};
};
return s;
};
int diag_left_down()
{
int n = 0;
int i = 0;
int r = 0;
int c = 19;
int a = 1;
for(n = 0;n <= 304;n++)
{
if(c >= 3 && r <= 16)
{
for(i = 0;i <= 3;i++)
{
//cout << " " << array[(r + i)][(c - i)] << " ";
a *= array[(r + i)][(c - i)];
};
//cout << a << " ";
i = 0; c--;
if(a > s)
{
s = a;
a = 1;
};
//cout << s << " " << endl;
a = 1;
}else{c = 19;
if(r <= 16){
r++;
}else{break;};
};
};
return s;
};
int diag_right_up()
{
int n = 0;
int i = 0;
int r = 19;
int c = 0;
int a = 1;
for(n = 0;n <= 304;n++)
{
if(c <= 16 && r >= 3)
{
for(i = 0;i <= 3;i++)
{
//cout << " " << array[(r - i)][(c + i)] << " ";
a *= array[(r - i)][(c + i)];
};
//cout << a << " ";
i = 0; c++;
if(a > s)
{
s = a;
a = 1;
};
//cout << s << " " << endl;
a = 1;
}else{c = 0;
if(r >= 3){
r--;
}else{break;};
};
};
return s;
};
int diag_right_down()
{
int n = 0;
int i = 0;
int r = 0;
int c = 0;
int a = 1;
for(n = 0;n <= 304;n++)
{
if(c <= 16 && r <= 16)
{
for(i = 0;i <= 3;i++)
{
//cout << " " << array[(r + i)][(c + i)] << " ";
a *= array[(r + i)][(c + i)];
};
//cout << a << " ";
i = 0; c++;
if(a > s)
{
s = a;
a = 1;
};
//cout << s << " " << endl;
a = 1;
}else{c = 0;
if(r <= 16){
r++;
}else{break;};
};
};
return s;
};
int main()
{
cout << "Result from right():" << '\t' << right();
cout << endl;
cout << "Result from left():" << '\t' << left();
cout << endl;
cout << "Result from down():" << '\t' << down();
cout << endl;
cout << "Result from up():" << '\t' << up();
cout << endl;
cout << "Result from diag_right_up(): " << '\t' << diag_right_up();
cout << endl;
cout << "Result from diag_right_down(): " << '\t' << diag_right_down();
cout << endl;
cout << "Result from diag_left_up(): " << '\t' << diag_left_up();
cout << endl;
cout << "Result from diag_left_down(): " << '\t' << diag_left_down();
cout << endl << endl << "Greatest result: " << s;
return 0;
}
The first thing I notice is that you've got a lot of functions that do basically the same thing (with some numbers different). I would investigate adding a couple of parameters to that function, so that you can describe the direction you're going. So for example, instead of calling right() you might call traverse(1, 0) and traverse(0, -1) instead of up().
Your traverse() function declaration might look like:
int traverse(int dx, int dy)
with the appropriate changes inside to adapt its behaviour for different values of dx and dy.
Well, for starters, you only need four of those directions: right/left, up/down, right-up/down-left and right-down/up-left. Multiplication is commutative, so it doesn't matter which direction you go from a given pair (if you find "a b c d" in one direction, you'll find "d c b a" in the opposite direction, and you get the same result when multiplying those numbers together).
Secondly, use more descriptive variable names. A variable name like s is meaningless; something like maximum is better, because that tells you what that variable is for. That doesn't mean you should never ever use a single-character variable name - e.g., using i as a for-loop counter is perfectly fine, and if you're dealing with coordinates, x and y can also be just fine, but when at all possible, you should use a descriptive name to make the code more self-documenting.
Thirdly, you can look into what Greg suggests and refactor your methods to take a direction instead. This would allow you to ditch all of the similar methods (and just call that one method 4 times with different parameters to cover all of the necessary directions).
And finally, you may want to be more consistent about your formatting - I know that can be hard to start doing, but it helps you in the long run. To understand what I mean here, take a good look at this snippet, taken from your down() method:
if(c <= 19)
{
for(i = 0;i <= 3;i++)
{
//cout << " " << array[(r + i)][c] << " ";
a *= array[(r + i)][c];
};
//cout << a << " ";
i = 0; c++;
if(a > s)
{
s = a;
a = 1;
};
//cout << s << " " << endl;
a = 1;
}else{c = 0;
if(r <= 16){
r++;
}else{break;};
};
Notice how you place a line break before the opening curly bracket of your ifs, but write }else{ on a single line. Additionally, inside the first else, you have another if-block where you don't place a line break before the curly bracket, and the closing bracket has the same indent level as the block content (r++;). This is quite inconsistent, and makes it harder to read.
static void largestProduct11() {
int[][] arr = {
{8, 2, 22, 97, 38, 15, 0, 40, 0, 75, 4, 5, 7, 78, 52, 12, 50, 77, 91, 8},
{49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48, 4, 56,
62, 0},
{81, 49, 31, 73, 55, 79, 14, 29, 93, 71, 40, 67, 53, 88, 30, 3, 49, 13,
36, 65},
{52, 70, 95, 23, 4, 60, 11, 42, 69, 24, 68, 56, 1, 32, 56, 71, 37, 2, 36,
91},
{22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33,
13, 80},
{24, 47, 32, 60, 99, 3, 45, 2, 44, 75, 33, 53, 78, 36, 84, 20, 35, 17,
12, 50},
{32, 98, 81, 28, 64, 23, 67, 10, 26, 38, 40, 67, 59, 54, 70, 66, 18, 38,
64, 70},
{67, 26, 20, 68, 2, 62, 12, 20, 95, 63, 94, 39, 63, 8, 40, 91, 66, 49, 94,
21},
{24, 55, 58, 5, 66, 73, 99, 26, 97, 17, 78, 78, 96, 83, 14, 88, 34, 89,
63, 72},
{21, 36, 23, 9, 75, 0, 76, 44, 20, 45, 35, 14, 0, 61, 33, 97, 34, 31, 33,
95},
{78, 17, 53, 28, 22, 75, 31, 67, 15, 94, 3, 80, 4, 62, 16, 14, 9, 53, 56,
92},
{16, 39, 5, 42, 96, 35, 31, 47, 55, 58, 88, 24, 0, 17, 54, 24, 36, 29, 85,
57},
{86, 56, 0, 48, 35, 71, 89, 7, 5, 44, 44, 37, 44, 60, 21, 58, 51, 54, 17,
58},
{19, 80, 81, 68, 5, 94, 47, 69, 28, 73, 92, 13, 86, 52, 17, 77, 4, 89, 55,
40},
{4, 52, 8, 83, 97, 35, 99, 16, 7, 97, 57, 32, 16, 26, 26, 79, 33, 27, 98,
66},
{88, 36, 68, 87, 57, 62, 20, 72, 3, 46, 33, 67, 46, 55, 12, 32, 63, 93,
53, 69},
{4, 42, 16, 73, 38, 25, 39, 11, 24, 94, 72, 18, 8, 46, 29, 32, 40, 62, 76,
36},
{20, 69, 36, 41, 72, 30, 23, 88, 34, 62, 99, 69, 82, 67, 59, 85, 74, 4,
36, 16},
{20, 73, 35, 29, 78, 31, 90, 1, 74, 31, 49, 71, 48, 86, 81, 16, 23, 57, 5,
54},
{1, 70, 54, 71, 83, 51, 54, 69, 16, 92, 33, 48, 61, 43, 52, 1, 89, 19, 67,
48}
};
/*
* |A11 A12 A13 * * A1N|
* |A21 A22 A23 * * A2N|
* |A31 A32 A33 A3N|
* * *
* * *
* |An1 A2N A3N * * ANN|
*
* */
String line;
int[] temp = new int[4];
int compre = 1;
int result = 1;
for (int i = 0; i < arr.length - 3; i++) { // optimize:- the condition is true
// if the remaining index are at least four therefore the length should be reduced by
// three that means only the first 16 members can can satisfy the condition
for (int j = 0; j < arr[0].length - 3; j++) {
result = arr[i][j] * arr[i + 1][j + 1] * arr[i + 2][j + 2] * arr[i + 3][j + 3];
if (compre < result) {
compre = result;
}
}
}
//
System.out.println(compre + " Right sie test ");
for (int i = 0; i < arr.length - 3; i++) {
line = "{";
for (int j = arr[0].length - 1; j > 3; j--) {
result = arr[i][j] * arr[i + 1][j - 1] * arr[i + 2][j - 2] * arr[i + 3][j
- 3];
if (compre < result) {
compre = result;
}
}
}
System.out.println(compre + " final result"); // solution= 70600674
}