C ++代码示例:这个循环多次出现的原因是什么?

时间:2013-03-05 23:00:08

标签: c++ recursion

我在这里找到了一个代码示例:N-QUEEN Backtracking problem solved

它显示了这段代码:

#include <iostream>
using namespace std;

/** this is the size of chess board */
#define N 8

/** Given a completed board, this prints it to the stdout */
void print_solution(int state[N][N])
{
    int i,j;
    for (i = 0; i < N; ++i)
    {
        for (j = 0; j < N; ++j)
            cout << state[i][j] << " ";
        cout << endl;
    }
    cout << endl;
}

/** return true if placing a queen on [row][col] is acceptable
else return false */
bool accept(int state[N][N], int row, int col)
{
    int i,j;

    /* check the column */
    for (i = 0; i < N; ++i)
    {
        if (state[row][i])
            return false;
    }

    /* check the row */
    for (i = 0; i < N; ++i)
    {
        if (state[i][col])
            return false;
    }

    /* check the upper left diagnol */
    for (i = row, j = col; i >= 0 && j >= 0; i--, j--)
    {
        if (state[i][j])
            return false;
    }

    /* check the lower left diagnol */
    for (i = row, j = col; i < N && j >= 0; ++i, --j)
    {
        if (state[i][j])
            return false;
    }

    /* check the upper right diagnol */
    for (i = row, j = col; i >= 0 && j < N; i--, ++j)
    {
        if (state[i][j])
            return false;
    }

    /* check the lower right diagnol */
    for (i = row, j = col; i < N && j < N; ++i, ++j)
    {
        if (state[i][j])
            return false;
    }

    /* return true if all tests passed */
    return true;
}

void solve_state(int state[N][N], int row)
{

    int i;

    /* if all queens have been placed at non conflicting positions */
    if (row == N)
    {

        print_solution(state);
        return;
    }

    /* Place queens on all positions in a given row and
    check if the state is acceptable
    Continue the process till all possibilities found */
    for(i=0; i<N; ++i){

        if(accept(state, row, i)){
            state[row][i] = 1;
            solve_state(state, row+1);
        }
        state[row][i] = 0;
    }
}

int main()
{
    /* initialise the board */
    int state[N][N] = {0};

    solve_state (state, 0);

    return 0;
}

我在逻辑上失败了,我在尝试学习递归等方面遇到了更多麻烦。让我感到震惊的是,我无法理解为什么这个代码在国际象棋问题中循环通过了8个皇后的所有92个解决方案。起初我以为它只找到了一个解决方案,但是一旦我测试了代码并且它运行了所有可能的解决方案,我感到很惊讶。

我必须在这里遗漏一些非常基本的东西,因为我甚至试图在一个解决方案之后让它“停止”,但我只是失败了。

所以我想我在这里问的是,为了理解这一点,给定这个代码,如果我只是想要循环一次,找到第一个解决方案,需要改变什么? / strong>什么样的巫术让这个东西一直循环?!

3 个答案:

答案 0 :(得分:1)

/* Place queens on all positions in a given row and
check if the state is acceptable
Continue the process till all possibilities found */
for(i=0; i<N; ++i){

    if(accept(state, row, i)){
        state[row][i] = 1;
        solve_state(state, row+1);
    }
    state[row][i] = 0;
}

这个循环正是你所描述的。您正在循环连续的八列,从而提供八种可能性。如果要停止在第一个可接受的状态,则必须更新内部条件并删除递归调用。相反,您可以调用print_solution函数打印结果。

这给你类似的东西:

for(i=0; i<N; ++i){

    if(accept(state, row, i)){
        state[row][i] = 1;
        print_solution(state);
        return; // this prevents printing the solution multiple times
                // in case the queen may be placed on other colum on the same row
    }
    state[row][i] = 0;
}

旁注:对我来说,这段代码是一个C代码(在函数开头声明的变量,普通的旧C数组,使用int,其中bool可以完成这项工作),以及唯一的C ++部分是在std::cout函数中使用std::endlprint_solution,可以很容易地被一个好的printf替换。

答案 1 :(得分:1)

理解递归方法的第一步是用语言表达方法的作用,如下所示:

/** solve_state(state, n) finds all possible solutions given a state where
 * the first n rows already have legally placed queens
 */

然后检查方法的主体并用语言表达:

/**
 * if n == N we're done, there is a queen in every row.  print the solution.
 * otherwise for every legal spot in the current row, 
 * put a queen there, and then solve the remaining rows.
 */

打印一个解决方案后退出程序的一个非常简单的方法是在打印解决方案后抛出异常。

或者,或许更优雅的是,您可以修改solve_state以在找到解决方案时返回1,并以这种方式停止递归:

int solve_state(int state[N][N], int row)
{
    int i;

    /* if all queens have been placed at non conflicting positions */
    if (row == N)
    {
        print_solution(state);
        return 1; // done!
    }

    /* Place queens on all positions in a given row and
       check if the state is acceptable
       Continue the process till all possibilities found */
    for(i=0; i<N; ++i){
        if(accept(state, row, i)){
            state[row][i] = 1;
            if (solve_state(state, row+1)) return 1;
        }
        state[row][i] = 0;
    }

    return 0; // not yet
}

答案 2 :(得分:0)

也许我的代码会帮助你,我不是最好的英语演讲者......

//coded by SwinGYOu

#include<iostream>
#pragma warning(disable:4996)
using namespace std;

/* this is the size of chess board */
const int boardSize=8;

/* Given a completed board, this prints it to the console */
void print_solution(int board[boardSize][boardSize], int i=0, int j=0){
    if(i==boardSize){ cout<<endl; return; }
    if(j==boardSize){ cout<<endl; print_solution(board, ++i, 0); return; }
    cout<<"[";
    if((i+j)%2)
        putwchar(board[i][j] ? '\u2655' : ' ');
    else
        putwchar(board[i][j] ? '\u265B' : ' ');
    cout<<"]";
    print_solution(board, i, ++j);
}
/* Check up, up left and up right to veritify that there are no other Queens, return true if right */
bool accept(int board[boardSize][boardSize], int row, int col, int rowD=0, int colD=0){
    if(!(rowD||colD)){
        return
            accept(board, row, col, -1, 0)&&
            accept(board, row, col, -1, -1)&&
            accept(board, row, col, -1, 1);
    }
    if(!(row>=0&&col>=0&&row<boardSize&&col<boardSize)){
        return true;
    }
    if(board[row][col]==1) return false;
    return accept(board, row+rowD, col+colD, rowD, colD);
}
/* check and return sultions for every sultion that possible*/
void solve_board(int board[boardSize][boardSize], int row=0, int col=0){
    //if the row befor was the last row of the table, its meants that is a sultion, print it.
    if(row==boardSize){
        print_solution(board);
        return;
    }
    //if col is out of the board, dont run check on it, its not a vaild path.
    if(col==boardSize) return;
    //run for this, if true, go to next row until end of row's or until a not vaild row is given than carry on with checking the next col.
    if(accept(board, row, col)){
        board[row][col]=1;
        solve_board(board, row+1);
    }
    board[row][col]=0;
    //carry on to next spot on the col in the given row.
    solve_board(board, row, col+1);
}

int main(){
    /* Make board */
    int board[boardSize][boardSize]={0};

    solve_board(board);

    return 0;
}