ошибка сегментации для проблемы более чем 9 ферзей - PullRequest
0 голосов
/ 07 мая 2020

Я читал «указатели на c» и нашел очень интересную проблему с 8 ферзями. Я пишу для него код, и он работает очень хорошо, и я получил правильный ответ, 92 решения.

Тогда я хочу попробовать более или менее ферзей. Я обнаружил очень странную проблему. Для 8 или менее 8 ферзей код работает идеально. Для более чем 8 ферзей, например 9,10 ..., будет ошибка сегментации.

Код, как показано ниже:

#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define SIZE 9

int conflict(int (*chess)[SIZE],int row,int col);
int next_queen(int (*chess)[SIZE],int row,int col);
int clear_previous_col(int (*chess)[SIZE],int col);
void print_chess_board(int (*chess)[SIZE]);

int total_solutions=0;
int total_print_count=0;
int chess[SIZE][SIZE];

int main(void)
{

    int row,col;

    /* initialize the chess board */
    for(row=0;row<SIZE;row++)
    {
        for(col=0;col<SIZE;col++)
        {
            chess[row][col]=0;
        }
    }

    /* start chess */
    next_queen(chess,0,0);
    printf("Totally %d solutions\n",total_solutions);

    return 0;
}

int next_queen(int (*chess)[SIZE],int row,int col)
{
    if(conflict(chess,row,col))
    {
        /* if conflicts, place queen in next row, make sure next row is not out of bound */
        if(row<SIZE-1)
        {
            next_queen(chess,row+1,col);
        }
        else
        {
             if(col<1)
             {
                 return -1;
             }
             else
             {
                 col=col-1;
                 int previous_queen_row;
                 while(col>=0 && (previous_queen_row=clear_previous_col(chess,col))==SIZE-1)
                 {
                     col=col-1;
                 }
                 if(col==-1)
                 {
                     return -1;
                 }
                 else
                 {
                     next_queen(chess,previous_queen_row+1,col);
                 }
             }
        }
    }
    else
    {
        chess[row][col]=1;
        if(col<SIZE-1)
        {
            next_queen(chess,0,col+1);
        }
        else
        {
        total_solutions++;
        print_chess_board(chess);
        chess[row][col]=0;
        col=col-1;
        int previous_queen_row;
        while(col>=0 && (previous_queen_row=clear_previous_col(chess,col))==SIZE-1)
        {
            col=col-1;
        }
        if(col==-1)
        {
            return -1;
        }
        else
        {
            next_queen(chess,previous_queen_row+1,col);
        }
        }
    }
    return 1;
}

void print_chess_board(int (*chess)[SIZE])
{
    int i,j;
    total_print_count++;
    if(total_print_count==152)
    {
        printf("stop here!\n");
    }
    printf("print number: %d\n",total_print_count);
    for(i=0;i<SIZE;i++)
    {
        for(j=0;j<SIZE;j++)
        {
            printf("%d ",chess[i][j]);
        }
        printf("\n");
    }
    printf("\n\n");
}

int clear_previous_col(int (*chess)[SIZE],int col)
{
    int i;
    for(i=0;i<SIZE;i++)
    {
        if(chess[i][col]==1)
        {
            chess[i][col]=0;
            return i;
        }
    }
    printf("return -1 col = %d\n",col);
    return -1;
}

int conflict(int (*chess)[SIZE],int row,int col)
{
    int i;
    int j;

    if(row>SIZE-1 || col>SIZE-1)
    {
        return TRUE;
    }

    if(row<0 || col<0)
    {
        return TRUE;
    }

    /* same row conflic */
    for(i=0;i<SIZE;i++)
    {
        if(chess[row][i]==1)
        {
            return TRUE;
        }
    }
    /* same column conflict */
    for(i=0;i<SIZE;i++)
    {
        if(chess[i][col]==1)
        {
            return TRUE;
        }
    }
    /* diagonally confilic */
    for(i=0;i<SIZE;i++)
    {
        for(j=0;j<SIZE;j++)
        {
            if(abs(i-row)>0 && abs(i-row)==abs(j-col) && chess[i][j]==1)
            {
                return TRUE;
            }
        }
    }
    return FALSE;
}

Ваша помощь очень признательна.

Спасибо.

Ответы [ 2 ]

1 голос
/ 07 мая 2020

Я запускал программу с valgrind в 64-битной системе Ubuntu 19.10.

Я не получал ошибки с #define SIZE 9.

С #define SIZE 10 он сообщает о переполнении стека.

Затем я запустил его с valgrind --num-callers=500, который является максимальным, и получил трассировку стека, подобную этой

==31854== Stack overflow in thread #1: can't grow stack to 0x1ffe801000
==31854==    at 0x109531: conflict (queen.c:138)
==31854==    by 0x10924C: next_queen (queen.c:39)
==31854==    by 0x109271: next_queen (queen.c:44)
==31854==    by 0x1092D7: next_queen (queen.c:66)
==31854==    by 0x1092D7: next_queen (queen.c:66)
==31854==    by 0x109271: next_queen (queen.c:44)
==31854==    by 0x109271: next_queen (queen.c:44)
==31854==    by 0x109271: next_queen (queen.c:44)
==31854==    by 0x109271: next_queen (queen.c:44)
==31854==    by 0x109271: next_queen (queen.c:44)
==31854==    by 0x109271: next_queen (queen.c:44)
==31854==    by 0x109271: next_queen (queen.c:44)
==31854==    by 0x1092D7: next_queen (queen.c:66)
==31854==    by 0x109271: next_queen (queen.c:44)
==31854==    by 0x109271: next_queen (queen.c:44)
==31854==    by 0x109271: next_queen (queen.c:44)
==31854==    by 0x109271: next_queen (queen.c:44)
==31854==    by 0x109271: next_queen (queen.c:44)
==31854==    by 0x109271: next_queen (queen.c:44)
...

с 499 записями для next_queen.

Вы могли бы имеют бесконечную рекурсию при некоторых условиях, но я предполагаю, что уровень вложенности становится слишком глубоким с большим размером платы.

Очевидно, предел для размера платы, который может быть вычислен с помощью вашего алгоритма, зависит от доступного размера стека, который отличается в разных системах или компиляторах.

0 голосов
/ 07 мая 2020

Вы получаете ошибку сегментации b c ваша программа запрашивает слишком много памяти. Подумайте об изменении вашего алгоритма. ферзь после того, как вы разместите нового ферзя.

При размещении нового ферзя вы просто проверяете свою текущую позицию. Если он равен 0, вы можете поставить ферзя и отметить его -1. И go увеличьте каждую клетку, которой угрожает ваш ферзь, на 1.

После того, как ваш рекурсивный вызов вернется, снова установите текущую клетку на 0 и уменьшите клетки под угрозой на 1 назад.

Таким образом ваша программа должна работать быстрее и использовать меньше памяти. Таким образом, на том же компьютере вы сможете увеличить размер без ошибок сегментации.

...