I am building a program to search for, identify, and mark the location of a graph of integer values in a simple two-dimensional array.
I hand traced the first example and it appeared to work out accurately. With that said I either wrote code that doesn't do what I think it does or my hand tracing was inaccurate.
I think my code is close and I'm looking for some debugging assistance and any thoughts on general style, etc.
Eventually this algorithm will be modified to find graphs of the pixels of characters for OCR. I simply want to prove that my algorithm implementation is accurate prior to complicating things with the code for processing images.
The input array might look like this:
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 0 0 0 0
0 0 0 0 0 0
and the expected outcome is this:
3 3 3 3 3 3
3 0 0 0 0 3
3 0 2 2 0 3
3 0 2 2 0 3
3 0 0 0 0 3
3 3 3 3 3 3
another similar possibility is:
in:
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 1 1 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
out:
0 3 3 3 3 3 3 0 0 0 0 0
0 3 0 0 0 0 3 0 0 0 0 0
0 3 0 2 2 0 3 0 0 0 0 0
0 3 0 2 2 0 3 0 0 0 0 0
0 3 0 0 0 0 3 0 0 0 0 0
0 3 3 3 3 3 3 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 3 3 3 3 3 3 3 3 3 0
0 0 3 0 0 0 0 0 0 0 3 0
0 0 3 0 2 2 2 2 2 0 3 0
0 0 3 0 0 0 0 0 0 0 3 0
0 0 3 3 3 3 3 3 3 3 3 0
Basic rules:
The array size of the input file must match the GS defined in the .cpp file (H equals W equals GS).
A graph is defined as one or more "1" values adjacent to each other.
The search is performed using a basic BFS technique using a simple queue.
When a graph is located its values will be updated from "1" to "2".
When the final value in the graph is determined a bounding box of "3" values will be drawn around the graph. The smallest X of the box equals the smallest X of the graph minus two, the smallest Y of the box equals the smallest Y of the graph minus two. The largest X of the box equals the largest X of the graph plus two, the largest Y of the box equals the largest Y of the graph plus two. Assume all graphs have a buffer of at least two rows/columns from the border to allow a box to be drawn.
The latest attempt of processing this array:
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0
0 0 0 1 1 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
yields this output:
0 0 0 0 0 0 0 0
0 3 3 3 3 3 0 0
0 3 3 3 3 3 3 0
0 3 3 2 1 3 3 0
0 3 3 2 2 3 3 0
0 3 3 3 3 3 3 0
0 3 3 3 3 3 3 0
0 0 0 0 0 0 0 0
while a single digit graph works well:
0 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
yields output:
3 3 3 3 3
3 0 0 0 3
3 0 2 0 3
3 0 0 0 3
3 3 3 3 3
Here is my code:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include "queue.h"
#define GS 8 /* GRID SIZE */
using namespace std;
void processCmdArgs (ifstream& input, int argc, char* argv[]);
void drawBoundingBox (int arr[][GS], int xLo, int yLo, int xHi, int yHi);
void checkNeighbors (int arr[][GS], bool vis[][GS], queue Q, point* p);
void print (int arr[][GS]);
int main( int argc, char* argv[] ) {
int xLo = 0;
int xHi = GS - 1;
int yLo = 0;
int yHi = GS - 1;
ifstream input; /* filestream to read in file to parse */
int arr[GS][GS]; /* declare array of vals to check for graph */
bool visited[GS][GS]; /* array of bools to track progress */
int count = 0; /* number of graphs found */
processCmdArgs(input, argc, argv);
/* populate array */
for (int i = 0; i < GS; i++) {
for (int j = 0; j < GS; j++) {
input >> arr[i][j];
}
}
input.close();
/*init visited */
for (int y = yLo; y < GS; y++) {
for (int x = xLo; x < GS; x++) {
visited[x][y] = false;
}
}
/* print array */
cout << "The array to find a graph is:\n";
print(arr);
/* find graph(s) in array */
queue Q;
for (int j = yLo; j < GS; j++) {
for (int k = xLo; k < GS; k++) {
if (arr[k][j] == 1) {
count++;
xLo = xHi = k;
yLo = yHi = j;
point *p = new point(k, j);
Q.insert(p);
delete p;
visited[k][j] = true;
while (!Q.isEmpty()) {
*p = Q.del(); /* does this really work? */
int x = p->getx();
int y = p->gety();
arr[x][y] = 2;
if (x < xLo) xLo = x;
if (y < yLo) yLo = y;
if (x > xHi) xHi = x;
if (y > yHi) yHi = y;
checkNeighbors(arr, visited, Q, p);
}
drawBoundingBox(arr, xLo, yLo, xHi, yHi);
}
else {
visited[k][j] = true;
}
}
}
cout << "The updated array is:\n";
print(arr);
cout << "The number of graphs in arr is " << count << endl;
return 0;
}
/*** END OF MAIN ***/
/*** START OF FUNCTIONS ***/
void processCmdArgs(ifstream& input, int argc, char* argv[]) {
/* Check command-line args first to avoid accessing nonexistent memory */
if (argc != 2) {
cerr << "Error: this program takes one command-line argument.\n";
exit(1);
}
/* Try to open the file using the provided filename */
input.open(argv[1]);
/* Exit with error if it doesn't open */
if (input.fail()) {
cerr << "Error: could not open " << argv[1] << ".\n";
exit(1);
}
}
void drawBoundingBox (int arr[][GS], int xLo, int yLo, int xHi, int yHi) {
// draw a box with (lowx-2,lowy-2) as NW and
// (highx + 2, highy + 2) as SE boundary
/* draw top and bottom of box */
for (int x = xLo - 2; x <= xHi + 2; x++) {
arr[x][yLo - 2] = 3;
arr[x][yHi + 2] = 3;
}
/* draw sides of box */
for (int y = yLo - 1; y <= yHi + 1; y++) {
arr[xLo - 2][y] = 3;
arr[xHi + 2][y] = 3;
}
}
void checkNeighbors (int arr[][GS], bool vis[][GS], queue Q, point* p) {
int pX = p->getx();
int pY = p->gety();
for (int y = pY - 1; y <= pY + 1; y++) {
for (int x = pX - 1; x <= pX + 1; x++) {
if (x == pX && y == pY) {/* easier than opposite boolean logic */ }
else {
if (vis[x][y] == false) vis[x][y] = true;
if (arr[x][y] == 1) {
point *n = new point(x, y);
Q.insert(n);
delete n;
}
}
}
}
}
void print (int arr[][GS]) {
/* print array */
for (int i = 0; i < GS; i++) {
for (int j = 0; j < GS; j++) {
cout << arr[i][j] << " ";
}
cout << endl;
}
}
/*** END OF FUNCTIONS ***/
/*** START of QUEUE CLASS ***/
const int MSIZE = 1000;
class point {
private:
int x; int y;
public:
point(int p, int q) {
x = p; y = q;
}
int getx() {
return x;
}
int gety() {
return y;
}
};
class queue {
private:
point* Q[MSIZE];
int front, rear, size;
public:
queue() {
// initialize an empty queue
//front = 0; rear = 0; size = 0;
front = rear = size = 0;
for (int j = 0; j < MSIZE; ++j)
Q[j] = 0;
}
void insert(point* x) {
if (size != MSIZE) {
front++; size++;
if (front == MSIZE) front = 0;
Q[front] = x;
}
}
point del() {
if (size != 0) {
rear++; if (rear == MSIZE) rear = 0;
point temp(Q[rear]->getx(), Q[rear]->gety());
size--;
return temp;
}
}
void print() {
for (int j = 1; j <= size; ++j) {
int i = front - j + 1;
cout << "x = " << Q[i]->getx() << " y = " << Q[i]->gety() << endl;
}
cout << "end of queue" << endl;
}
bool isEmpty() {
return (size == 0);
}
};
/*** END of QUEUE CLASS ***/
This code does not compile. You've left out `queue.h`. We can infer it, but you shouldn't make us do that.
You have class declarations in this source file; they belong in the header file (otherwise there isn't much point in having a header file).
If you're going to have class declarations in the source file, for heaven's sake put them before the code that needs them.
There's a simple compile-time bug in `queue::del()`. Either your compiler isn't very good, or you've turned off warnings, or you're ignoring warnings, or you can't be bothered to fix the easy stuff.
Is there some good reason you're using arrays instead of STL containers?
Is there some good reason you're declaring all of these points on the heap?
I don't want to jump to conclusions, but the logic in your main loop looks really confused and over-complicated.
Most important: If you were to dispense with the bounding box, I very much doubt that the program would run bug-free, and the bugs would be much easier to find. Did you try that before writing code for the bounding box? You should test each new behavior as you put it in, and never add to code that doesn't work. (I say that so often I should start calling it "Beta's Rule".)
Now let's look for bugs...
In the main loop, you iterate from `xLo` and `yLo`, but you modify those variables in the loop.
Sometimes you index with `[j][k]`, sometimes with `[k][j]`. When I clean that up, some of the bad behavior disappears.
You're drawing a separate bounding box around every point of the graph.
There's a simple off-by-one bug in you bounding box routine.
And now it works, for one graph. I'm not going to try it with two.
EDIT:
I have to eat some of my words: you don't index with [j][k], I was just confused by your use of (k,j) <=> (x,y) and got it mixed up with an actual bug elsewhere. And now I see what you're doing with the queue, but seriously you should look into the STL.
The really serious bug is in the signature of checkNeighbors(...). You're passing Q by value, not by reference. Fix that, and the code works for multiple graphs.
EDIT:
Yep, another bug: queue stores pointers to points, not points, for no particular reason (see "6", above), and somehow it's fouling them up. Rather than hunt down the exact bug, I changed queue to handle points, and got the correct result for the complicated graph.
Related
I want to read a file called maze.txt which contains 0s and 1s (indicated blocked or not), and store every element in the file into 2 dimensionals array called maze[17][17].
maze.txt be like :
11111111111111111
10000000000101001
10100111111001101
10101100001010101
10111010100000001
10000011011111001
11111000010001001
10110010000100101
10110100101110111
10000111000100001
10110011000100101
10110010000011101
10111001111110101
10110010000010001
10010111110101111
10010000000000001
11111111111111111
What I've searched the closest answer is using getline() plus istringstream()
(refer to : Read from file in c++ till end of line?)
But above solution only applies when I put a whitespace between each of them, like :
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1
1 0 1 0 0 1 1 1 1 1 1 0 0 1 1 0 1
1 0 1 0 1 1 0 0 0 0 1 0 1 0 1 0 1
1 0 1 1 1 0 1 0 1 0 0 0 0 0 0 0 1
1 0 0 0 0 0 1 1 0 1 1 1 1 1 0 0 1
1 1 1 1 1 0 0 0 0 1 0 0 0 1 0 0 1
1 0 1 1 0 0 1 0 0 0 0 1 0 0 1 0 1
1 0 1 1 0 1 0 0 1 0 1 1 1 0 1 1 1
1 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 1
1 0 1 1 0 0 1 1 0 0 0 1 0 0 1 0 1
1 0 1 1 0 0 1 0 0 0 0 0 1 1 1 0 1
1 0 1 1 1 0 0 1 1 1 1 1 1 0 1 0 1
1 0 1 1 0 0 1 0 0 0 0 0 1 0 0 0 1
1 0 0 1 0 1 1 1 1 1 0 1 0 1 1 1 1
1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
My code:
void read_maze(int map[17][17]) {
ifstream read_file("D:/maze.txt", ios::in);
if (read_file.good()){
string str;
int i = 0;
while (getline(read_file, str) {
int j = 0;
istringstream ss(str);
int num;
while (ss >> num)
{
map[i][j] = num;
j++;
}
i++;
}
}
for (int i = 0; i < 17; i++)
{
for (int j = 0; j < 17; j++)
{
cout << map[i][j];
}
cout << endl;
}
read_file.close();
}
output is like original maze.txt
So, what should I do to store each of the element in maze.txt into an array without modifying the content of it?
I believe there might be some easier solutions to it, but since I'm a newbie to C++, I can't find any of similar situations like me.
Hope someone can provide detailed code based on above code.
Thanks a lot!
You can do it like this :
#include <array>
#include <iostream>
#include <string>
#include <sstream>
std::istringstream file{
"11111111111111111\n"
"10000000000101001\n"
"10100111111001101\n"
"10101100001010101\n"
"10111010100000001\n"
"10000011011111001\n"
"11111000010001001\n"
"10110010000100101\n"
"10110100101110111\n"
"10000111000100001\n"
"10110011000100101\n"
"10110010000011101\n"
"10111001111110101\n"
"10110010000010001\n"
"10010111110101111\n"
"10010000000000001\n"
"11111111111111111\n"
};
auto load(std::istream& is)
{
// use std::array, you can actually return that from functions
// and avoids the pain of having to work with double pointers
// and manual memory managment.
std::array<std::array<char, 17>, 17> map{};
// loop over all rows in the map
for (auto& row : map)
{
// loop over all the values in a row
for (auto& value : row)
{
// read one value from the file
is >> value;
}
// newlines will be skipped.
}
// and return your map (2d array)
return map;
}
int main()
{
// file is a stringstream now but
// is easily replaced by a filestream
// (stringstream just makes testing more easy)
auto map = load(file);
// just another range based for loop
// to display the map we read from file.
for (const auto& row : map)
{
for (const auto& value : row)
{
std::cout << value;
}
std::cout << "\n";
}
}
Your code would work with a slight modification. Like this:
#include <fstream>
#include <iostream>
#include <sstream>
using namespace std;
void read_maze(int map[17][17]) {
ifstream read_file("maze.txt", ios::in);
if (read_file.good()){
string str;
int i = 0;
while (getline(read_file, str)) {
// read line and process each digit
for (int j=0; j < str.size(); j++) {
map[i][j] = str[j] - '0';
}
i++;
}
}
for (int i = 0; i < 17; i++)
{
for (int j = 0; j < 17; j++)
{
cout << map[i][j] << " ";
}
cout << endl;
}
read_file.close();
}
int main() {
int map[17][17] = {};
read_maze(map);
}
I am facing this wierd problem which has left me with no clue and I am not able to figure out the issue. Below is the problem statement.
There are 100 teams participating (numbered 1 to 100) in a competition trying to solve 9 problems. A team may not be able to solve any problem, in which case the total_solved problems and total_time will be zero. For the sake of easiness, I am maintaining a static vector with size as 100. The name stores the team number (1 to 100) . I am using active flag to know that a team submitted at least 1 solution (even wrong).
Here is the class team :
class team
{
public:
int total_solved;
int time[9];
int total_time;
bool solved[9];
bool active;
int name;
team()
{
total_solved = total_time = 0;
active = false;
name = -1;
for(int i=0;i<9;i++)
{
solved[i] = false;
time[i] = 0;
}
}
};
Here is the vector:
for(int i=0;i<100;i++)
{
record.push_back(new team());
}
Somewhere later, I fill the data about the teams. Here is the dump of the data corresponding to these teams :
cout << "Dumping the data\n";
for(auto it=record.begin();it!=record.end();it++)
{
cout << (*it)->name << " " << (*it)->total_solved << " " << (*it)->total_time << " " << ((*it)->active?'Y':'N') << endl;
}
cout << "That's all\n";
Dumping the data
-1 0 0 N
2 0 0 Y
-1 0 0 N
-1 0 0 N
5 0 0 Y
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
24 0 0 Y
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
34 0 0 Y
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
41 0 0 Y
-1 0 0 N
-1 0 0 N
-1 0 0 N
45 0 0 Y
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
58 0 0 Y
-1 0 0 N
-1 0 0 N
-1 0 0 N
62 0 0 Y
-1 0 0 N
64 0 0 Y
-1 0 0 N
-1 0 0 N
67 0 0 Y
-1 0 0 N
69 0 0 Y
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
78 0 0 Y
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
-1 0 0 N
That's all
You can see that no team has solved any problem in this specific case. And some teams are not active (did not submit any solution, name as -1 or active as false denotes that). The crash happens when I try to sort this 100 team data. The sorting criteria is that teams must solve max problems in min time. If there is a tie, we will sort as per team number ignoring the inactive ones.
bool compare(team *t1, team *t2)
{
if(t1->total_solved != t2->total_solved)
return t1->total_solved > t2->total_solved;
if(t1->total_time != t2->total_time)
return t1->total_time < t2->total_time;
return t1->active;
}
sort(record.begin(),record.end(),compare);
I analysed through gdb, I get the following :
Program received signal SIGSEGV, Segmentation fault.
0x00005555555552d0 in compare (t1=0x55555576fec0, t2=0x411) at 10258.cpp:33
33 if(t1->total_solved != t2->total_solved)
t2 is definitely getting invalid pointer, but I wonder why?
EDIT
Here is the compilable version : https://ideone.com/bcnmE0 with sample input.
Your comparison function is incorrect. Comparison functions should return true if the first parameter is 'less than' the second parameter. But yours returns true (all other things being equal) if t1->active is true. This means your function could return true for two teams which are equal (if both had active as true). Incorrect comparison functions can cause sorting algorithms to crash. Try this instead
bool compare(team *t1, team *t2)
{
if(t1->total_solved != t2->total_solved)
return t1->total_solved > t2->total_solved;
if(t1->total_time != t2->total_time)
return t1->total_time < t2->total_time;
return t1->active > t2->active;
}
or this
return t1->active < t2->active;
Either way you return false for two equal teams.
As already described, you need to make your comparison function meet the requirements for Compare. In addition to that, your comparison function did not take the team name into consideration when the other fields compared equal. I took bits from your example # ideone and made a MCVE out of it with the bugs fixed:
#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
#include <array>
class team {
public:
int total_solved;
std::array<int, 9> time;
int total_time;
std::array<bool, 9> solved;
bool active;
int name;
team(int Name) :
total_solved{0},
time{},
total_time{0},
solved{},
active{false},
name(Name)
{}
inline bool operator<(team const& t2) const {
if(total_solved != t2.total_solved)
return total_solved > t2.total_solved;
if(total_time != t2.total_time)
return total_time < t2.total_time;
// return t1->active; // bug
if(active != t2.active) // bug-fix
return active > t2.active; // -"-
// the below was specified as the last sorting criteria
// but wasn't included in your actual code:
return name < t2.name;
}
friend std::ostream& operator<<(std::ostream&, const team&);
};
std::ostream& operator<<(std::ostream& os, const team& t) {
os << t.name << " " << t.total_solved << " "
<< t.total_time << " " << (t.active?"Y":"N") << "\n";
return os;
}
int main() {
// bug-fix: making sure the teams are deleted using std::unique_ptr
std::vector<std::unique_ptr<team>> record;
for(int i=1; i<=100; ++i)
record.emplace_back(new team(i));
for(auto contestant : {41,67,34,2,69,24,78,58,62,64,5,45})
record[contestant-1]->active = true;
std::cout << "Dumping the data\n";
for(auto& t : record) std::cout << *t;
std::sort(record.begin(), record.end(),
[](std::unique_ptr<team> const& a, std::unique_ptr<team> const& b) {
return *a < *b;
}
);
std::cout << "After sort\n";
for(auto& t : record) std::cout << *t;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
How to write in C++ 2D array with diagonally numbers for
n - size of array (width and height)
x - how many the same number in a row
c - how many numbers must be used
example for
n = 5
x = 2
c = 2
output is:
0 0 1 1 0
0 1 1 0 0
1 1 0 0 1
1 0 0 1 1
0 0 1 1 0
My current code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
int n=0, x=0, c=0;
int temp_x=0,temp_c=-1;
cin >> n >> x >> c;
c--;
for(int i=0; i<n;i++){
for(int j=0; j<n;j++){
cout << ++temp_c;
temp_x++;
if(temp_x>x){
temp_x=0;
if(temp_c=c){
temp_c=-1;
}
}
}
cout << endl;
}
}
I will be grateful for your help. :)
But my code return incorrectly number :(
Are you trying to do this?
int main()
{
int n=0, x=0, c=0;
int temp_x=0,temp_c=0;
cin >> n >> x >> c;
c--;
for(int i=0; i<n;i++){
for(int j=0; j<n;j++){
if(temp_x<x)
{
temp_x++;
cout << temp_c << " ";
continue;
}
temp_c++;
temp_x=0;
if(temp_c>c)
{
temp_c=0;
}
cout << temp_c << " ";
temp_x++;
}
cout << endl;
}
}
Output:
5 2 2
0 0 1 1 0
0 1 1 0 0
1 1 0 0 1
1 0 0 1 1
0 0 1 1 0
5 2 3
0 0 1 1 2
2 0 0 1 1
2 2 0 0 1
1 2 2 0 0
1 1 2 2 0
5 3 2
0 0 0 1 1
1 0 0 0 1
1 1 0 0 0
1 1 1 0 0
0 1 1 1 0
I'd like to propose another algorithm:
Run It Online !
#include <iostream>
#include <vector>
#include <numeric> // iota
using std::cout;
using std::endl;
void fill(const size_t n ///< size of array (width and height)
, const size_t x ///< how many the same number in a row
, const size_t c) ///< how many numbers must be used
{
// generate the sequence of possible numbers
std::vector<int> numbers(c);
std::iota(numbers.begin(), numbers.end(), 0);
//std::vector<int> all(n * n); // for storing the output, if needed
for (size_t i = 0, // element index
k = 0, // "number" index
elements = n * n; // the square matrix can also be viewed as a n*n-long, 1D array
i < elements;
k = (k + 1) % c) // next number (and the modulus is for circling back to index 0)
{
// print the number "x" times
for (size_t j = 0; j < x && i < elements; ++j, ++i)
{
// break the line every "n" prints
if ((i % n) == 0)
{
cout << endl;
}
//all[i] = numbers[k];
cout << numbers[k] << " ";
}
}
cout << endl;
}
int main()
{
fill(5, 2, 2);
}
Output for fill(5, 2, 2)
0 0 1 1 0
0 1 1 0 0
1 1 0 0 1
1 0 0 1 1
0 0 1 1 0
In C++ if I have a square array int board[8][8] that's filled like this:
0 0 1 0 0 0 0 0
0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
0 0 0 0 1 0 0 0
0 0 0 0 0 0 1 0
0 1 0 0 0 0 0 0
What's the shortest way to check if any of the 1's share a row, column, or diagonal with another 1?
edit: I said most efficient when I really meant shortest
8 x 8 board? This must be related to chess or something.
Here's a clever way to test if any piece is on hit by the queen (i.e. almost identical to whether a 1 shares a row, column or diagonal with another 1).
bool CG_queen::move(File f_to, Rank r_to, File f_from, Rank r_from)
{
bool canMakeMove = false;
//Check to see if Queen is moving only by File or only by Rank.
//aka, only vertically or horizontally.
if ( f_from == f_to || r_from == r_to )
{
canMakeMove = true;
}
//Check to see if Queen only moves diagonally.
if ( abs(f_from - f_to) == abs(r_to - r_from) )
{
canMakeMove = true;
}
return canMakeMove;
}
You can use a bitmask for the rows, columns and diagonals to indicate if there is a 1 on any of them:
int rowMask = 0;
int ColumnMask = 0;
int diagonalMask0 = 0;
int diagonalMask1 = 0;
for(int i = 0; i < 8; i++)
{
for(int j = 0; j < 8; j++)
{
if(board[i][j])
{
// test row:
if(rowMask & (1 << i))
return true;
rowMask |= 1 << i; // mark row set
// test column:
if(columnMask & (1 << j))
return true;
columnMask |= 1 << j; // mark column set
// test first diagonal:
if(diagonalMask0 & (1 << (i + j)))
return true;
diagonalMask0 |= 1 << (i + j); // mark diagonal set
// test first diagonal:
if(diagonalMask1 & (1 << (8 + i - j)))
return true;
diagonalMask1 |= 1 << (8 + i - j); // mark diagonal set
}
}
}
return false;
If there is an element set in a particular row, the bit for that row is tested in rowMask. If it is already set then return true, otherwise set it using a bitwise OR so other elements can be tested against it. Do likewise for columns and the diagonals.
The following code is supposed to find the minimum spanning tree from a adjacency matrix:
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <conio.h>
#include <vector>
#include <string>
using namespace std;
int i, j, k, a, b, u, v, n, ne = 1;
int min, mincost = 0, cost[9][9], parent[9];
int find(int);
int uni(int, int);
int find(int i)
{
while (parent[i]) // Error occurs at this line
i = parent[i];
return i;
}
int uni(int i, int j)
{
if (i != j)
{
parent[j] = i;
return 1;
}
return 0;
}
int main()
{
cout << "MST Kruskal:\n=================================\n";
cout << "\nNo. of vertices: ";
cin >> n;
cout << "\nAdjacency matrix:\n\n";
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
cin >> cost[i][j];
if (cost[i][j] == 0)
cost[i][j] = 999;
}
}
cout << "\nMST Edge:\n\n";
while (ne < n)
{
for (i = 1, min = 999; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
if (cost[i][j] < min)
{
min = cost[i][j];
a = u = i;
b = v = j;
}
}
}
u = find(u);
v = find(v);
if (uni(u, v))
{
cout << ne++ << "th" << " edge " << "(" << a << "," << b << ")" << " = " << min << endl;
mincost += min;
}
cost[a][b] = cost[b][a] = 999;
}
cout << "\nMinimum cost = " << mincost << "\n" << endl;
system("PAUSE");
return 0;
}
It works for 6 number of vertices and the following matrix:
0 3 1 6 0 0
3 0 5 0 3 0
1 5 0 5 6 4
6 0 5 0 0 2
0 3 6 0 0 6
0 0 4 2 6 0
however for 13 vertices and with the following matrix:
0 1 0 0 0 2 6 0 0 0 0 0 0
1 0 1 2 4 0 0 0 0 0 0 0 0
0 1 0 0 4 0 0 0 0 0 0 0 0
0 2 0 0 2 1 0 0 0 0 0 0 0
0 4 4 2 0 2 1 0 0 0 0 4 0
2 0 0 1 2 0 0 0 0 0 0 2 0
6 0 0 0 1 0 0 3 0 1 0 5 0
0 0 0 0 0 0 3 0 2 0 0 0 0
0 0 0 0 0 0 0 2 0 0 1 0 0
0 0 0 0 0 0 1 0 0 0 1 3 2
0 0 0 0 0 0 0 0 1 1 0 0 0
0 0 0 0 4 2 5 0 0 3 0 0 1
0 0 0 0 0 0 0 0 0 2 0 1 0
this error occurs:
Unhandled exception at 0x00ED5811 in KruskalMST.exe: 0xC0000005: Access violation reading location 0x00F67A1C.
The error occurs at line 17: while (parent[i])
VS Autos:
Name Value Type
i 138596 int
parent 0x00ee048c {2, 999, 999, 999, 999, 999, 999, 999, 2} int[9]
[0] 2 int
[1] 999 int
[2] 999 int
[3] 999 int
[4] 999 int
[5] 999 int
[6] 999 int
[7] 999 int
[8] 2 int
You've defined your 'parent' array to have a size of 9 (assuming you have a maximum of 9 vertices, so max number of parents is 9). Six vertices will work because it's less than 9. With thirteen vertices you MAY be accessing elements passed your parent array size; thus, you should try and define your array size depending on the number of vertices.
P.S In general you don't want to have magic numbers in your code.
while (parent[i])
{
i = parent[i];
}
First of all, please use braces to enclose the while statement. Anyone adding another line to it would likely cause undesired behavior.
Your problem is likely that parent[i] assigns a value to i that is outside of the bounds of the parent array.
Try this to see what it's assigning to i:
while (parent[i] != 0)
{
cout << "parent[i] is " << parent[i];
i = parent[i];
}
Since the parent array has a size of 9, if i is ever set to 9 or greater (or less than 0 somehow), you may get an access violation when using parent[i].
Unrelated: It's good to be explicit about what condition you're checking in the while. Before I saw that parent was an int[], I didn't know if it might be an array of pointers, or booleans, I didn't know what the while condition was checking for.
If you want to be safe, bounds check your parent array:
static const int parentSize = 9;
int parent[parentSize];
while (parent[i] != 0 && i > 0 && i < parentSize)
{
cout << "parent[i] is " << parent[i];
i = parent[i];
}
You likely need to increase the parentSize to something larger. If you want something that is more dynamic you might considering using std::vector instead of an array, it can be resized at runtime if you run into a case where the container isn't large enough.