Pixel distance flood-fill - c++

Problem statement:
Input is a rectangular bitmap like this:
0001
0011
0110
The task is to find for each black (0) "pixel", the distance to the
closest white (1) "pixel". So, the output to the above should be:
3 2 1 0
2 1 0 0
1 0 0 1
I have a working solution to the problem, which I posted here, asking for advice on performance improvement. In effort to implement #Jerry Coffin's solution (suggested in an answer to the question) I wrote the following code, which, unfortunately, produces garbage output. For example, the output for the input from the problem statement is
1 1 1 0
11 11 0 0
110 0 0 1
Why doesn't the code work?
#include <iostream>
#include <string>
#include <queue>
using namespace std;
const unsigned short MAX = 200;
typedef unsigned short coordinate;
typedef pair<coordinate,coordinate> coordinates;
//Converts char[] to unsigned int
coordinate atou(char* s) {
coordinate x = 0;
while(*s) x = x*10 + *(s++) - '0';
return x;
}
//Returns array of immediate neighbours of pixel of coordinates c
coordinates* neighbours_of(coordinates c) {
static coordinates neighbours[7];
coordinate i = c.first;
coordinate j = c.second;
neighbours[0] = coordinates(i+1,j);
neighbours[1] = coordinates(i+1,j+1);
neighbours[2] = coordinates(i,j+1);
neighbours[3] = coordinates(i-1,j+1);
neighbours[4] = coordinates(i-1,j);
neighbours[5] = coordinates(i-1,j-1);
neighbours[6] = coordinates(i,j-1);
neighbours[7] = coordinates(i+1,j-1);
return neighbours;
}
int main() {
unsigned short test_cases, wave_number, initial_wave_size;
coordinate m, n, i, j;
int A[MAX][MAX];
coordinates* directions;
string row;
queue<coordinates> ones;
queue<coordinates> wave;
coordinates current_coordinates;
bool found_some_zero;
cin >> test_cases;
while(test_cases--) {
//Input
cin >> n;
cin >> m;
for(i = 0; i < n; i++) {
cin >> row;
for(j = 0; j < m; j++) {
if(row[j] == '1') {
A[i][j] = -1;
ones.push(coordinates(i,j));
} else A[i][j] = atou(&row[j]);
}
}
//Initilization
wave = ones;
wave_number = 1;
found_some_zero = true;
//Filling algorithm
while(found_some_zero) {
found_some_zero = false;
initial_wave_size = wave.size();
while(initial_wave_size--) {
current_coordinates = wave.front();
directions = neighbours_of(current_coordinates);
//Try all directions
for(int k = 0; k < 8; k++) {
i = directions[k].first;
j = directions[k].second;
//If on screen and not yet visited
if(i < n && j < m && A[i][j] == 0) {
//Mark visited
A[i][j] = wave_number;
//(i,j) will be part the next wave
wave.push(coordinates(i,j));
found_some_zero = true;
}
}
wave.pop();
}
wave_number++;
}
//-1 to 0
while(!ones.empty()) {
current_coordinates = ones.front();
i = current_coordinates.first;
j = current_coordinates.second;
A[i][j] = 0;
ones.pop();
}
//Output
for(i = 0; i < n; i++) {
for(j = 0; j < m; j++)
cout << A[i][j] << " ";
cout << endl;
}
}
return 0;
}

The input loop is buggy. Instead of
if(row[j] == '1') {
A[i][j] = -1;
ones.push(coordinates(i,j));
} else A[i][j] = atou(&row[j]);
you need to do
if(row[j] == '1') {
A[i][j] = -1;
ones.push(coordinates(i,j));
} else A[i][j] = 0;
Also, neighbors[7] should be neighbors[8], and you should use only the four cardinal directions if you want to match the specified output exactly.

Related

C++ problem "Find the last position of -1(negative one)"

Position of "-1".
In the given NxM matrix find the LAST position of the minus one(-1).
If it will be no "-1" value in the given matrix just output "-1 -1".
Input
First line N and M (1<=N,M<=100).
Then NxM table is given(all number are integers)
Output
First number have to be the row number,and then column number of last "-1" element.
Here is my solution. But I have wrong answer.
#include <iostream>
#include <climits>
using namespace std;
int main () {
int row, col;
double x = 0, y = 0;
cin >> row >> col;
int matrix[row][col];
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
cin >> matrix[i][j];
if (matrix[i][j] < 0) {
x = i + 1;
y = j + 1;
}
}
}
if (x == 0 && y == 0)
x = -1, y = -1;
cout << x << " " <<y;
}
Some potential problems:
if (matrix[i][j] < 0) does not check for -1 only. Any negative value will make that condition true.
Unless explicitly specified, I would assume that they want the coordinates with a 0-base, not a 1-base, which would make x = i + 1; and y = j + 1; wrong.
cout << x << " " <<y; is confusing - but you seem to have assigned the row to x and the column to y so I guess it would work if the condition and assignments above were ok.
int matrix[row][col]; is not standard C++. A standard version would be std::vector<std::vector<int>> matrix(row, std::vector<int>(col));
... but - since you only need to print the last position where a -1 is entered, you don't need to store the whole array.
Just read the numbers one by one and check if the entered number is -1. If it is, store the position.
Example:
#include <iostream>
int main () {
int row, col;
int x = -1, y = -1; // if no -1 is found, these will still be -1
if(!(std::cin >> row >> col) || row < 1 || col < 1) return 1;
int value;
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if(!(std::cin >> value)) return 1;
if(value == -1) { // -1 entered, store the position
y = i;
x = j;
}
}
}
std::cout << y << ' ' << x << '\n';
}

Improve on binary converting algorithm (include negative numbers)

I'm doing some C++ array homework. The goals is to convert decimal to binary (include negative numbers). Here's my code, it gets the job done, but I would like to see if anything can be improved, or any better algorithm (using binary shift maybe?).
#include <iostream>
using namespace std;
// doi tu thap phan sang nhi phan
void decToBinary(int n, int nhiphan[])
{
for (int i=0; i < 16; i++)
{
// to binary
nhiphan[i] = n % 2;
n = n / 2;
}
// inverse array
for (int i = 0, j = 15; i < j; i++, j--)
{
int temp = nhiphan[i];
nhiphan[i] = nhiphan[j];
nhiphan[j] = temp;
}
}
void reverse(int& a)
{
if (a == 0)
a++;
else a--;
}
void outArr(const int a[], int size) {
for (int i = 0; i < size; ++i)
cout << a[i];
}
int main()
{
int nhiphan[16];
int n;
do {
cout << "Nhap so (-255 <= n <= 255) chuyen doi sang nhi phan (16 bit): ";
cin >> n;
} while (n > 255 || n < -255);
if (n < 0) {//check negative
n *= -1;
decToBinary(n, nhiphan);
for (int i = 0; i < 16; i++)// 1's complement
reverse(nhiphan[i]);
// +1
if (nhiphan[15] == 0)//2's complement
nhiphan[15] = 1;
else
{
nhiphan[15] = 0;
int i = 15;
do {
reverse(nhiphan[i-1]);
i--;
} while (nhiphan[i-1] == 0);
}
}
else decToBinary(n, nhiphan);
outArr(nhiphan, 16);
return 0;
}

How do you find the location of a number in a sequence?

Say that I have a sequence:
int seq[4][4];
Then, lets say seq[1][2]=8;
No other values of the sequence yields 8.
If I want to find the values of a sequence and print out which one it is, (e.g. 1,2 and make x=1 and y=2) how can I do that? What
int x,j;
for (int i = 0; i < 4; i++) // looping through row
{
for(int j = 0; j < 4; j++) //looping through column
{
if (seq[i][j] == 8) //if value matches
{
x = i; y = j; //set value
i = 4; //set i to 4 to exit outer for loop
break; //exit inner for loop
}
}
}
int numberBeingSearchedFor = *Any Value Here*;
int array[*numRows*][*numColumns*];
int firstOccuranceRow = -1, firstOccuranceColumn = -1;
for(int i = 0; i < numRows; ++i)
{
for(int j = 0; j < numColumns; ++j)
{
if(array[i][j] == numberBeingSearchedFor)
{
firstOccuranceRow = i;
firstOccuranceColumn = j;
i = numRows; //Credit to other answer, I've never seen that :) It's cool
break;
}
}
}
if(firstOccuranceRow == -1 || firstOccuranceColumn == -1)
{
//Item was not in the array
}

Puzzle related to sorting a 2-D array in ascending order

A randomly generated 4x4 2-D array is given to the user, of which one element is definitely 0. Considering 0 to be an empty location, the user will have to exchange the remaining 15 elements with 0 repeatedly until they get the array in ascending order, with 0 as the last element.
At this point, they're allowed to exchange any element with 0.
But how do I modify this code to ensure that are only able to exchange those elements with 0 that are adjacent to it (either above, below or beside it) ?
#include<iostream>
#include<stdlib.h>
#include<time.h>
using namespace std;
int check_asc(int a[][4])
{
int i, j, previous = a[0][0];
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
if(i == 3 && j == 3)
{
if (a[i][j] == 0)
return 1;
}
else if (a[i][j] < previous)
{
return 0;
}
previous = a[i][j];
}
}
return 1;
}
void swap(int a[][4], int &xpos, int &ypos)
{
int arr, temp;
cout << "\n\nEnter number to be swapped with 0: ";
cin >> arr;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (a[i][j] == arr)
{
temp = a[xpos][ypos];
a[xpos][ypos] = a[i][j];
a[i][j] = temp;
xpos = i;
ypos = j;
return;
}
}
}
}
int check_rep(int a[][4], int assign)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (assign == a[i][j])
return 0;
}
}
return 1;
}
void main()
{
int a[4][4], assign, xpos = 0, ypos = 0, asc_result, rep_result;
srand((unsigned)time(NULL));
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
{
if (i == 0 && j == 0)
a[i][j] = 0;
else
{
do {
assign = rand() % 50;
rep_result = check_rep(a, assign);
} while (rep_result == 0);
a[i][j] = assign;
}
}
cout << "\n\nArrange the 4x4 matrix into ascending order. (Consider 0 as a blank space)" << endl;
for (int i = 0; i < 4; i++)
{
cout << endl;
for (int j = 0; j < 4; j++)
cout << a[i][j] << '\t';
}
do {
swap(a, xpos, ypos);
system("cls");
for (int i = 0; i < 4; i++)
{
cout << endl;
for (int j = 0; j < 4; j++)
cout << a[i][j] << '\t';
}
asc_result = check_asc(a);
} while (asc_result == 0);
cout << "\n\tYou win"<<endl;
system("pause");
}
Simple, just extend your swap function with a piece of code that will check whether the location of the element to be swapped is adjacent to the location of 0:
void swap(int a[][4], int &xpos, int &ypos)
{
...
if (a[i][j] == arr &&
((i == xpos && (j == ypos - 1 || j == ypos + 1)) ||
(j == ypos && (i == xpos - 1 || i == xpos + 1))))
{
temp = a[xpos][ypos];
a[xpos][ypos] = a[i][j];
a[i][j] = temp;
xpos = i;
ypos = j;
return;
}
An improvement would be to separate the check condition and inform the user in case when the element is not adjacent to 0.
Rough Algorithm
1) create a function find location, it will return a structure Point that has x, y integer fields, it will find the x, y location of any piece based on the pieces value, i.e. lets say 0 is entered, if it is located in the top left corner (0,0), a point (0, 0) will be returned
2) create a function that takes in 2 points, the location of the '0' and the location of the piece we wish to swap lets call it S, if S.x = 0.x and 0.y - 1 = S.y or S.y - 0.y + 1 then you know that said piece is directly above or below the 0, now of course you have ot add a few conditions for boundaries so as we dont check outside the grid. Have this function return an int 1 if the piece S is located above/below/beside, 0 if not.
3) if 1 is returned your allowed to do the flip, if 0 is returned find another piece

Character / int equality evaluating incorrectly

Background info: I'm writing a C++ program to solve sudoku puzzles, and I've hit a major road block. The general flow of the program is like this:
Iterate through the grid and check if a 0 can be replaced with a number. (blanks are represented by 0s)
Check in 3 dimensions (vertical, horizontal, and in the box) which numbers are already there.
Determine if we can narrow that number down to one possibility, replace it, then move on.
Repeat until grid has no zeros
I'm running into issues at the second step, I'll post the whole program at the bottom, but only relevant code here.
int* check_v(string g, size_t x, size_t y){
int *ans = new int[9]; //array of possible ints
memset(ans, 0, sizeof(ans)); //set array to all 0s
size_t size = 0;
for(int i = 1; i < 10; i++){ //iterate through 1-10
//check if i is in the col, if it isn't then add i to ans
bool placeable = true;
for(size_t j = 0; j < 9; j++){ //iterate through ints in the col
size_t r = (j + x) % 9; //the string is a 9x9 grid of numbers
cout << get(g,r,y) << " == " << i << " is " << (get(g,r,y) - 0 == i - 0);
//this is my debug statement, because the if below isn't working.
if(get(g,r,y) - 0 == i - 0){ //if i is equal to a num in the grid,
placeable = false;//we know it can't be that number
}
}
if(placeable) ans[size++] = i; //only add i if we didn't find it in the grid
}
return ans;
}
This is one of the methods that checks the column for each number to see what numbers are/aren't there yet.
Here's the relevant get() method:
char get(string g, size_t x, size_t y){
return g.at(x * 9 + y);
}
Where g is a string of numbers 0-9 81 letters long. It's a 9x9 grid, but put into one long string.
So the get(g,r,y) returns a char like '6', and i is an int. I do '6' - 0 to make them both ints, and compare them. However, it's always false! Even when i = 6 and get(g,r,y) = '6'. Am I doing my comparisons wrong? I must have a typo somewhere and I just don't see it. Here's some sample output from that cout call, and I'll post the whole file for context.
//output
0 == 1 is 0
3 == 1 is 0
8 == 1 is 0
2 == 1 is 0
5 == 1 is 0
7 == 1 is 0
4 == 1 is 0
9 == 1 is 0
6 == 1 is 0 //this is all right, there aren't any 1s in the col
0 == 2 is 0
3 == 2 is 0
8 == 2 is 0
2 == 2 is 0 //but this is wrong! why isn't this true?
5 == 2 is 0
7 == 2 is 0
4 == 2 is 0
9 == 2 is 0
6 == 2 is 0
Now here's the entire file to give you the whole picture.
using namespace std;
#include <iostream>
#include <cstring>
void print(string g){
for(size_t i = 0; i < 9; i++){
for(size_t j = 0; j < 9; j++){
cout << g.at(i * 9 + j);
}
cout << endl;
}
}
void set(string & g, size_t x, size_t y, char z){
size_t i = x * 9 + y;
string beg = g.substr(0,i);
string end = g.substr(i+1,g.length());
g = beg + z + end;
}
char get(string g, size_t x, size_t y){
return g.at(x * 9 + y);
}
int* check_v(string g, size_t x, size_t y){
int *ans = new int[9];
memset(ans, 0, sizeof(ans));
size_t size = 0;
for(int i = 1; i < 10; i++){
bool placeable = true;
for(size_t j = 0; j < 9; j++){
size_t r = (j + x) % 9;
cout << get(g,r,y) << " == " << i << " is " << (get(g,r,y) - 0 == i - 0) << endl;
if(get(g,r,y) - 0 == i - 0){
placeable = false;
}
}
if(placeable) ans[size++] = i;
}
return ans;
}
int* check_b(string g, size_t x, size_t y){
int *ans = new int[9];
memset(ans, 0, sizeof(ans));
size_t size = 0;
x = x / 3 * 3;
y = y / 3 * 3;
for(size_t i = 0; i < 3; i++){
bool placeable = true;
for(size_t j = 0; j < 3; j++)
if(get(g,x + i, y + j) == static_cast<char>(i))
placeable = false;
if(placeable) ans[size++] = i;
}
return ans;
}
int* check_h(string g, size_t x, size_t y){
int *ans = new int[9];
memset(ans, 0, sizeof(ans));
size_t size;
for(size_t i = 1; i < 10; i++){
bool placeable = true;
for(size_t j = 0; j < 9; j++){
cout << get(g,x,(j + y) % 9) << " == " << i << endl;
if(get(g,x,(y + j) % 9) == static_cast<char>(i)){
placeable = false;
}
}
if(placeable) ans[size++] = i;
}
return ans;
}
void check(string g, size_t x, size_t y){
int *n_v = check_v(g, x, y);
int *n_h = check_h(g, x, y);
int *n_b = check_b(g, x, y);
int n_y[9] = {0};
int n;
size_t size = 0;
cout << "vert: ";
for (int i = 0; i < 9; i++)
cout << n_v[i];
cout << endl << "hor: ";
for (int i = 0; i < 9; i++)
cout << n_h[i];
cout << endl << "box: ";
for (int i = 0; i < 9; i++)
cout << n_b[i];
cout << endl;
if(n_v[0] == 0 || n_h[0] == 0 || n_b[0] == 0)
cout << "Error, no number works in slot " << x << ", " << y << endl;
else{
if(n_v[1] == 0)
n = n_v[0];
else if(n_h[1] == 0)
n = n_h[0];
else if(n_b[1] == 0)
n = n_b[0];
}
for(size_t i = 0; i < 9; i++){
bool possible = true;
for(size_t j = 0; possible && j < 9; j++){
if(n_h[j] != n_v[i])
possible = false;
}
for(size_t j = 0; possible && j < 9; j++){
if(n_b[j] != n_v[i])
possible = false;
}
if(possible)
n_y[size++] = n_v[i];
}
if(n_y[1] == 0)
n = n_y[0];
if(n != 0){
char c = n;
set(g,x,y,c);
}
}
int main(){
//initializations
size_t dim = 9;
string data = "";
string one_row;
for (size_t r = 0; r < dim ; r = r + 1) {
cin >> one_row;
data += one_row;
}
//start solving
bool cont = true;
while(cont){
cont = false;
for(size_t i = 0; i < data.length(); i ++){
if(data.at(i) == '0'){
cont = true;
cout << "Checking at point " << i / 9 << ", " << i % 9 << endl;
string old = data;
check(data, i / 9, i % 9);
if(old.compare(data) != 0)
print(data);
}
}
}
print(data);
}
This:
if(get(g,r,y) - 0 == i - 0)
Doesn't work. If get returns a char, it's a character from a string representing the CODE of the number. You're subtracting an integer 0 from that, which is not subtracting anything. What you want is either
if(get(g,r,y) - '0' == i)
Or
if(get(g,r,y) == i + '0')
Which assumes ascii (not unicode or something else).
What you're attempting to do is "convert" between an ascii CHARACTER and an integer. You do that conversion to one or the other, not both. The difference between 0 and '0' is that the first is an integer zero, the second is a character of 0 as would be found in a string.
(get(g,r,y) - 0 == i - 0);
This is wrong. Use it instead.
(get(g,r,y) - '0' == i - 0);