回溯法

来源:互联网 发布:聊天记录查询软件 编辑:程序博客网 时间:2024/04/29 10:24

重学算法-回溯法

1.背景


解决n皇后问题常用的方法是回溯法。回溯法本质上也是遍历所有解空间的方法。下面就以n皇后问题为例,介绍回溯法。

2.例子


n皇后问题。在n×n棋盘上放置n个皇后,使她们不会互相攻击。

3.算法思想


用回溯法有几个条件。(1)解的空间是已知的。(2)每个解都有判定条件。(3)每个解都有规模。

以n皇后问题为例:(1)解的空间是1,2,...,n的排列。(2)判定条件是横、竖、斜都不能有多于1个皇后。(3)解的规模就是n。只有在棋盘上摆上n个皇后,才能满足条件。

4.算法描述


用board[n]=m表示在第n行的m列摆上皇后
(1)首先board[0]=0,在第一行摆第一个皇后
(2)如果满足判定条件,且解的规模也达到目标,则输出
(3)如果满足判定条件,但解的规模还没到,则扩充解的规模。board[1]=0,...,board[n-1]=0
(4)如果不满足判定条件,则修改当前解,得到下个解。从(2)开始重复。board[1]++。如果board[1]已经达到最大值,就board[0]++。这个过程叫回溯。直到不能回溯,(board[-1]++),结束。

5.代码

 

#include <stdio.h>


//output
void OutBoard(int board[],int n)
...{
    
int k,i;
    
static int count=0;
    count
++;
    printf(
"count=%d/n",count);
    
for (i=0;i<n;i++)
    
...{
        
for(k=0;k<n;k++)
        
...{
            
if(board[i]==k)
                printf(
"");
            
else
                printf(
"");
        }

        printf(
"/n");
    }

    printf(
"/n");
}


//check if queens will attach each other
bool IsInterAttack(int board[],int row)
...{
    
int i,k;
    
for(i=0;i<row;i++)
    
...{
        
for(k=0;k<row;k++)
        
...{
            
if(k==i) continue;
            
//check column
            if(board[i] == board[k]) return true;
            
//check slash diagonal direction
            if(i+board[i] == board[k] + k) return true;
            
//check back slash diagonal direction
            if(i-board[i] == k-board[k]) return true;
        }

    }

    
return false;
}


//main algorithms
void Queen(int n)
...{
    
int i;
    
int *board=new int[n];
    i
=0;
    board[
0]=0;
    
while(i>=0)
    
...{
        
if(!IsInterAttack(board,i+1))
        
...{
            
if(i==n-1)
            
...{
                OutBoard(board,n);    
                i
--;            
            }

            
else
            
...{
                i
++;
                board[i]
=0;
                
continue;
            }

        }
        
        
else
        
...{
            
if(board[i]<n-1)
            
...{
                board[i]
++;
                
continue;
            }

            
else
            
...{
                i
--;
            }

        }


        
while(i>=0)
        
...{
            
if(board[i]<n-1)
            
...{
                board[i]
++;
                
break;
            }

            
else
            
...{
                i
--;
            }

        }

    }


    delete [] board;
}


//main
int main()
...{    
    Queen(
4);
    
return 0;
}

 

6.运行结果

count=1
O * O O
O O O *
* O O O
O O * O

count
=2
O O * O
* O O O
O O O *
O * O O

7.进一步思考


回溯法的思想就是基本这样的。但例子中的代码不是最优的。我是用IsInterAttack函数来判断是否符合判定条件。我在别人的代码中看到有用三个数组来判断横、竖、斜是否符合判定条件的。例如a[n]=1代表第n列已经有皇后了,x[column+row]=1代表右高左低的斜线上已经有皇后了等等。

原创粉丝点击