I'm trying to solve the 8 queens puzzle problem in C. I'm having problems with the recursive search. The program is supposed to start at a given column:
execute(tabuleiro,8,0);
Where the 8 is the number of columns in the board, and 0 is the start column.
This works when I start at column 0. When I send any other column number to the recursive search, the program just counts to the last column. For example, if I choose to start the search from the number 5 column, the code search from the column 5 to 7, after this it should search from 0 to 4, but it doesn't do that.
If I do this:
execute(tabuleiro,8,3);
It fills in only the last 5 colummns, and does not return to column 0 to finish the solution:
Also, how can I select the initial position for the queen in this code? Like I said before, the column is assigned in the code, but I'm not sure how to pick the correct column.
The code has 3 functions: one is to display the board, a second to check if the move is legal (so one queen doesn't attack the other), and the last one to place one queen and recur for the remainder of the board.
#include <stdlib.h>
#include <windows.h>
int sol = 0;
void viewtab(int tab[][8], int N)
{
int i,j;
for( i = 0; i < N; i++)
{
for( j = 0; j < N; j++)
{
if(tab[i][j] == 1)
printf("R\t");
else
printf("-\t");
}
printf("\n\n");
}
printf("\n\n");
system("pause");
printf("\n");
}
int secury(int tab[][8], int N, int lin, int col)
{
// this function is to check if the move is secury
int i, j;
// attack in line
for(i = 0; i < N; i++)
{
if(tab[lin][i] == 1)
return 0;
}
//attack in colune
for(i = 0; i < N; i++)
{
if(tab[i][col] == 1)
return 0;
}
// attack in main diagonal
//
for(i = lin, j = col; i >= 0 && j >= 0; i--, j--)
{
if(tab[i][j] == 1)
return 0;
}
for(i = lin, j = col; i < N && j < N; i++, j++)
{
if(tab[i][j] == 1)
return 0;
}
// attack in main secondary
for(i = lin, j = col; i >= 0 && j < N; i--, j++)
{
if(tab[i][j] == 1)
return 0;
}
for(i = lin, j = col; i < N && j >= 0; i++, j--)
{
if(tab[i][j] == 1)
return 0;
}
// if arrive here the move is secury and return true
return 1;
}
void execute(int tab[][8], int N, int col)
{
int i;
if(col == N)
{
printf("Solution %d ::\n\n", sol + 1);
viewtab(tab, N);
sol++;
return;
}
for( i = 0; i < N; i++)
{
// check if is secury to put the queen at that colune
if(secury(tab, N, i, col))
{
// insert the queen (with 1)
tab[i][col] = 1;
// call recursive
execute(tab, N, col + 1);
// remove queen (backtracking)
tab[i][col] = 0;
}
}
}
int main()
{
int i, j, tabuleiro[8][8];
for (i = 0; i < 8; i = i + 1)
for (j = 0; j < 8; j = j + 1) tabuleiro[i][j] = 0;
execute(tabuleiro,8,0);
return 0;
}
The search always stops in the rightmost column because you specifically tell it to stop there:
void execute(int tab[][8], int N, int col)
{
int i;
if(col == N)
{
printf("Solution %d ::\n\n", sol + 1);
viewtab(tab, N);
sol++;
return;
}
Look at your termination condition: you check the current column against the highest column number, and stop there.
If you want to go back to column 0, you have to change your loop logic. For instance, let col reach N, at which point you reset it to 0, and let it continue until you hit the original value. Another way is to continue until the count of placed queens is N.
You choose the initial point in the same way: you pick the first one and make your recursive call. If that eventually results in a solution, you print it. If not, your top-most call continues to the next row (line) of the board and puts the first queen there.
This is already in your main logic. Just make sure that secury will return true when the board is empty, rather than false or throwing an error.
A. You can place the first Queen at (0,0).
B. And begin the search also from (0,0).
C. I do not see any need to start looking for some other index.
Successfully!!
Related
So here is the problem: Write a program that accept an integer n, print out the largest number but smaller or equal n that is the product of two consecutive even number. Example: Input: 12, Output: 8 ( 2x4 )
Here is my code :
#include <stdio.h>
int main()
{
int n;
scanf("%d", &n);
for (int i = n; i >= 0; i--)
{
for (int j = 0; j <= n; j = j + 2)
{
if ( i == j * (j+2) )
{
printf("%d ", i);
break;
}
}
}
return 0;
}
So if i input 20, it will print out 8 and 0 instead of 8, if i input 30, it will print out 24,8 and 0 instead of just 24. How do i make it stop after printing out the first number that appropriate ?
You need to stop an outer loop from processing, for example by using a boolean flag (meaning "solution found, we finish work") or a goto statement.
#include <stdio.h>
int main() {
int n;
scanf("%d", &n);
int solutionFound = 0;
for (int i = n; i >= 0; i--) {
// this could also be put into for's condition i.e. "i >= 0 && !solutionFound"
if (solutionFound) {
break;
}
for (int j = 0; j <= n; j = j + 2) {
if ( i == j * (j+2) ) {
printf("%d ", i);
solutionFound = 1;
break;
}
}
}
return 0;
}
EDIT: immediate return as noted in the comments is also a nice idea, if you don't need to do anything later.
Your problem is that you are nested - in a for loop which is inside another for loop - when you want to stop processing.
Some languages would let you code break 2; to indicate that you want to break out of 2 loops. Alas, C i snot such a language.
I would recommend that you code a function. That would serve a few porpoises: 1) your main should be "lean & mean" 2) as your programs get larger, you will learn the benefits of putting individual coding tasks into functions 3) you can use return; instead of break; and it will exit the function immediately.
Something like this:
#include <stdio.h>
void FindNeighbouringDivisors(int n)
{
for (int i = n; i >= 0; i--)
{
for (int j = 0; j <= n; j = j + 2)
{
if ( i == j * (j+2) )
{
printf("%d times %d = %d", j, j + 2, i);
return;
}
}
}
printf("There are no two adjacent even numbers which can be multiplied to give %d", n);
}
int main()
{
int n;
scanf("%d", &n); /* could get from comamnd line */
FindNeighbouringDivisors(n);
return 0; /* should be EXIT_SUCCESS */
}
Btw, when you have a problem with your code, ask a question here. When you have it working, consider posting it at our code review site where more experienced programmers can give you advice on how to improve it. It's a great way to learn
Break only breaks you out of immediate loop, so either use flags or just use return to terminate the execution. Or you can even use following code:
#include <stdio.h>
int main()
{
int n;
scanf("%d", &n);
for (int j = 0; j <= n; j = j + 2)
{
if ( n < j * (j+2) )
{
printf("%d ", j*(j-2));
break;
}
}
return 0;
}
so I've been struggling with this example for a good hour now and I can't even begin to process how should I do this.
Write a program that, for given n and m, forms a matrix as described.
The matrix should be m x m, and it's filled "spirally" with it's
beginning in the upper left corner. The first value in the matrix is
the number n. It's repeated until the "edge" of the matrix, at which
point the number increments. After the number 9 goes 0. 0 ≤ n ≤ 9, 0 ≤
m ≤ 9
Some time ago I had made a function to display the numbers 1 to n on an odd-sized grid.
The principle was to start from the center and to shift by ;
x = 1
x box on the right
x box on the bottom
x++
x box on the left
x box at the top
x++
With this simple algorithm, you can easily imagine to maybe start from the center of your problem and decrement your value, it seems easier to start from the center.
Here is the code that illustrates the above solution, to be adapted of course for your problem, it's only a lead.
#define WE 5
void clock(int grid[WE][WE])
{
int count;
int i;
int reach;
int flag;
int tab[2] = {WE / 2, WE / 2}; //x , y
count = 0;
flag = 0;
i = 0;
reach = 1;
grid[tab[1]][tab[0]] = count;
for (int j = 0; j < WE - 1 && grid[0][WE - 1] != pow(WE, 2) - 1; j++)
for (i = 0; i < reach && grid[0][WE - 1] != pow(WE, 2) - 1; i++, reach++)
{
if(flag % 2 == 0)
{
for(int right = 0 ; right < reach ; right++, tab[0]++, count++, flag = 1)
grid[tab[1]][tab[0]] = count;
if(reach < WE - 1)
for(int bottom = 0; bottom < reach; bottom++, count++, tab[1]++)
grid[tab[1]][tab[0]] = count;
}
else
{
for(int left = 0; left < reach; left++, count++, tab[0]--, flag = 0)
grid[tab[1]][tab[0]] = count;
for(int top = 0; top < reach; top++, tab[1]--, count++)
grid[tab[1]][tab[0]] = count;
}
}
}
I finally solved it. If anybody's interested, here's how I did it:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
//Fills the row number "row" with the number n
int fillRow(int m, int n, int arr[m][m], int row)
{
int j;
for(j=0;j<m;j++)
{
if(arr[row][j] == -1 || arr[row][j] == n-1) arr[row][j] = n;
}
}
//Fills the column number "col" with the number n
int fillCol(int m, int n, int arr[m][m], int col)
{
int i;
for(i=0;i<m;i++)
{
if(arr[i][col] == -1 || arr[i][col] == n-1) arr[i][col] = n;
}
}
int main()
{
int n, m, i, j, r=1, c=1, row=-1, col=-1;
scanf("%d %d",&n, &m);
int arr[m][m];
//Fill array with -1 everywhere
for(i=0;i<m;i++)
{
for(j=0;j<m;j++)
{
arr[i][j] = -1;
}
}
//Calculate which row/column to fill (variables row/col)
//Fill row then column then row than column...
for(i=0;i<2*m;i++)
{
if(i%2==0)
{
row = (r%2==0) ? m-r/2 : r/2;
fillRow(m, n, arr, row);
n++;
r++;
}
else if(i%2==1)
{
col = (c%2==0) ? c/2-1 : m-c/2-1;
fillCol(m, n, arr, col);
n++;
c++;
}
}
//If an element is larger than 9, decrease it by 10
//Prints the elements
for(i=0;i<m;i++)
{
for(j=0;j<m;j++)
{
if(arr[i][j]>9) arr[i][j] -=10;
printf("%d ",arr[i][j]);
}
printf("\n");
}
return 0;
}
I want to output Yay if the matrix doesn't contain the same number on the same row or column otherwise output Nay
this is for my college homework. I already tried to check the column and row in the same loop but the output still not right
#include <stdio.h>
int main()
{
int size;
int flag;
scanf("%d",&size);
char matrix[size][size];
for (int i = 0; i < size; i++)
{
for (int l = 0; l < size; l++)
{
scanf("%s",&matrix[i]);
}
}
for (int j = 0; j < size; j++){
for (int k = 0; k < size; k++){
if(matrix[j] == matrix[j+1] || matrix[j][k]==matrix[j][k+1])
{
flag = 1;
}
else
{
flag = 0;
}
}
}
if (flag == 1)
{
printf("Nay\n");
}
else
{
printf("Yay\n");
}
return 0;
}
I expect to output "Nay" when I input
3
1 2 3
1 2 3
2 1 3
and "Yay" when i input
3
1 2 3
2 3 1
3 1 2
Your matrix is a 2D array and you are referencing it using only a single subscript matrix[index] at several places which returns the address of the row. Index it using both the row and column indices. Try the code below:
{
int size;
int flag;
scanf("%d",&size);
char matrix[size][size];
for (int i = 0; i < size; i++)
{
for (int l = 0; l < size; l++)
{
scanf("%s",&matrix[i][l]);
}
}
for(int j = 0; j < size; j++){
for (int k = 0; j < size; j++){
if(matrix[j][0]== matrix[j][k] || matrix[k][0]==matrix[k][j])
{
flag = 1;
break;
}
else
{
flag = 0;
}
}
}
if (flag == 1)
{
printf("Nay\n");
}
else
{
printf("Yay\n");
}
return 0;
}
Your have a logic problem. Your flag is reset on every element in the matrix and thus only reflects the result of the last check.
In addition, you need a break; in your nested loop. The logic is, if your flag becomes 1, you are sure to say Nay, and you don't want the flag to be reset to 0.
int flag = 0;
for (int i = 0; i != size && !flag; ++i) {
for (int j = 0; j != size; ++j) {
if ( /* detection */ ) {
flag = 1;
break;
}
}
}
if (flag)
printf("Nay\n");
else
printf("Yay\n");
Note: The commented /* detection */ part requires more work. Since it's your homework, you may try it first. You could use a hash table for memorization. Or brutal force to make the program simply work. It seems that your detection only checks for neighboring elements, which is not sufficient to assert that an element is unique in its row or column. Consider
1 2 1
3 4 5
6 7 8
I can't do your homework for you. The following is the brutal-force way you may consider.
The if ( /* detection */ ) part could be if (has_same_element(matrix, i, j)), with a function (pseudo code)
int has_same_element(matrix, row, col)
{
for each element a in matrix's row except matrix[row][col] itself
if (a == matrix[row][col])
return 1
for each element b in matrix's col except matrix[row][col] itself
if (b == matrix[row][col])
return 1
return 0
}
Of course there are smarter ways, like using a hash table, in which case you don't even need the nested loop. For the time being, work out a feasible solution, instead of the best solution.
#include <stdio.h>
#include <math.h>
int n=4;
int GetQueenSettings(int board[4][4],int currentRow,int n)
{
//decide when the recursion stops
if(currentRow==n)
return 1; //successful setting
//otherwise we set column by column in this row and continue
int TotalSettingCount=0;
for(int i=0;i<n;i++)
{
//make sure it can be set (it is unset at that moment)
if(board[currentRow][i]==0)
{
board[currentRow][i]==1+currentRow;
//use row related info for settings
//now set invalid positions for remaining rows
setInvalid(board,currentRow,n,i);
//recover after this before trying the next
TotalSettingCount += GetQueenSettings(board,currentRow+1,n);
board[currentRow][i]=0;
RecoverBoard(board,currentRow,n);
}
}
return TotalSettingCount;
}
void setInvalid(int board[4][4],int currentRow,int n,int i)
{
//vertical and diagonal elements
for(int row=currentRow+1;row<n;row++) //start from the next line
{
//firstly make sure board can be set
if(board[row][i]==0)//vertical position
board[row][i]=-(1+currentRow);
//now check diagonal
int rowGap=row-currentRow;
if(i-rowGap>=0 && board[row][i-rowGap]==0)
{
//left bottom diagonal position
board[row][i-rowGap]=-(1+currentRow);
}
if(i+rowGap<n && board[row][i+rowGap]==0)
{
//bottom right diagonal position
board[row][i+rowGap]=-(1+currentRow);
}
}
}
void RecoverBoard(int board[4][4],int currentRow,int n)
{
//recover is to check all remaining rows if index is higher than current row(setters)
//OR less than -currentRow(invalids)!
for(int row=currentRow+1;row<n;row++)
{
for(int col=0;col<n;col++)
{
if(board[row][col]>currentRow || board[row][col]< -currentRow)
board[row][col]=0;
}
}
}
int main()
{
int board[n][n];
printf("Number of settings:-> %d",GetQueenSettings(board,0,n));
return 0;
}
There are N queeens placed on a NxN chessboard without interfering with each other. when i run this code i get the answer as zero instead of 2 . also i cant figure out a way of passing array board to functions with variable size(size will be given by user).What am i doing wrong?!
You should initialize your board. As is, you start with a board full of garbage values. You are using a variable-length array as board. Such arrays cannot be initialized, so you have to set the board to all zero with a loop or with memset from <string.h>:
int board[n][n];
memset(board, 0, sizeof(board));
You can pass variable-length arrays to functions when the dimensions are passed in as earlier arguments, for example:
int GetQueenSettings(int n, int board[n][n], int currentRow) { ... }
Also fix the =/== switch in setInvalid:
if (board[row][i] == 0)
board[row][i] = -(1 + currentRow);
Finally make sure that all functions have proper prototypes when they are called.
A loooooooong time ago I developed an algorithm like the one you have, maybe it can help you.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
long Solutions;
void AllocBoard(int *** Board, int Queens)
{
int i;
*Board = (int **)malloc(sizeof(int *) * Queens);
for(i = 0; i < Queens; i++)
{
(*Board)[i] = (int *)malloc(sizeof(int) * Queens);
memset((*Board)[i], 0, sizeof(int) * Queens);
}
}
void DeallocBoard(int *** Board, int Queens)
{
int i;
for(i = 0; i < Queens; i++)
free((*Board)[i]);
free(*Board);
}
void SavePosition(int *** Board, int Queens, int Col, int Row, int Inc)
{
int i, j;
for(i = 0; i < Queens; i++)
{
if((*Board)[Col][i] >= 0) (*Board)[Col][i] += Inc;
if((*Board)[i][Row] >= 0) (*Board)[i][Row] += Inc;
}
for(i = Col, j = Row; j < Queens && i < Queens; i++, j++)
if((*Board)[i][j] >= 0) (*Board)[i][j] += Inc;
for(i = Col, j = Row; j >= 0 && i >= Col; i--, j--)
if((*Board)[i][j] >= 0) (*Board)[Col][j] += Inc;
for(i = Col, j = Row; j >= 0 && i < Queens; i++, j--)
if((*Board)[i][j] >= 0) (*Board)[i][j] += Inc;
for(i = Col, j = Row; j < Queens && i >= Col; i--, j++)
if((*Board)[i][j] >= 0) (*Board)[i][j] += Inc;
}
void FindSolutions(int *** Board, int Queens, int Col)
{
int i, j;
for(i = 0; i < Queens; i++)
{
if((*Board)[Col][i] != 0) continue;
(*Board)[Col][i] = -1;
if(Col + 1 == Queens)
Solutions++;
else
{
SavePosition(Board, Queens, Col, i, 1);
FindSolutions(Board, Queens, Col + 1);
SavePosition(Board, Queens, Col, i, -1);
}
(*Board)[Col][i] = 0;
}
}
void main(int argc, char **argv)
{
int Queens, ** Board = NULL;
clock_t Start, End;
clrscr();
if(argc < 2)
Queens = 8;
else
Queens = atoi(argv[1]);
Solutions = 0;
Start = clock();
AllocBoard(&Board, Queens);
FindSolutions(&Board, Queens, 0);
DeallocBoard(&Board, Queens);
End = clock();
printf("Solutions %ld\n", Solutions);
printf("Estimated time: %f", (End - Start) / CLK_TCK);
getch();
}
Hope this helps
Asking "why it doesn't work" about short and simple programs is not very well. Try debug it yourself with any debugger or simply using printing in important places/on each step. Actually, C has no arrays, instead it has pointers. You can work with them very alike, that is why all you need is to change int board[4][4] to int **board and add one argument: int N(count of cells) and that's all. All your other code shouldn't be changed.
I'm doing another exercise and I have to :
"Write a recursive function to print all solution to the eight queens chess problem, return the number of solutions and the function prototype must be : int function(void)
To work around the no argument rule I used static variables.
I've done it (with google's help), and it works, but they don't allow to use for loops and for some reason I can't manage to convert the last two for loops to while loops.
It' driving me crazy, it should be easy! I think it's the recursion that mess it up...
Here's the working function :
int function()
{
static int count = 0;
static int col = 0;
const int n = 8;
static int hist[8] = {10, 10, 10, 10, 10, 10, 10, 10};
int i1 = 0;
if (col == n) {
count++;
while (i1++ < n)
{
putchar('0' + hist[i1-1] + 1);
}
putchar('\n');
}
for (int i = 0; i < n; i++) {
int j = 0;
for (j = 0; j < col && !(hist[j] == i || (hist[j] - i) == col - j || -(hist[j] - i) == col - j); j++);
if (j < col) {
continue;
}
hist[col] = i;
col++;
function();
col--;
}
return count;
}
And I tried to convert the two last for loops to while loops like this :
int i = 0;
while (i < n)
{
int j = 0;
while (j < col && !(hist[j] == i || (hist[j] - i) == col - j || -(hist[j] - i) == col - j))
{
j++;
}
if (j < col) {
continue;
}
hist[col] = i;
col++;
function();
col--;
i++;
}
But it doesn't work, is there more the for loops than it seems ? I'm new to recursion, I thought I got it but it seems I was wrong...
I ran the code and found the problem. It is with the line
if (j < col) {
continue;
}
since this isn't a continue statement that goes to a for loop, you have to increment i in this condition as well.
if (j < col) {
i++; // add this line
continue;
}
You can change the first loop to
while(i++<n)
and it works fine.