今天数据结构课上讲到了递归回溯法,用到了三个著名的例子。便想着干出来来加深下理解
这个当初学完离散数学就写了个出来。原理简单,就是一直往前冲,没路就回溯,看之前走过的地方有没有别的方向可以走。有实时打印的功能方便看走迷宫的实时情况,还用栈实现了打印全称路径。直接上代码
#include <iostream>
#include <stack>
#include <windows.h>
using namespace std;
struct point{
int x;
int y;
};//坐标结构体
const int dx[]={0,1,0,-1};
const int dy[]={-1,0,1,0};//down right up left;
const int MAXROW=10,MAXCOLUMN=10;//迷宫长宽
//标记为0的点为可走,1的点不可走,2的点已经走过
int maze[MAXROW][MAXCOLUMN]={
1,1,1,1,1,1,1,1,1,1,
0,0,0,1,1,1,1,1,1,1,
1,1,0,1,1,1,1,1,1,1,
1,1,0,0,0,0,1,1,1,1,
1,1,0,1,1,0,1,1,1,1,
1,1,0,1,1,0,1,1,1,1,
1,1,1,1,1,0,1,1,1,1,
1,1,1,1,1,0,0,0,1,1,
1,1,1,1,1,1,1,0,0,0,
1,1,1,1,1,1,1,1,1,1,
};
void displayMaze(){
for(int i=0;i<MAXROW;i++){
for(int j=0;j<MAXCOLUMN;j++){
if(maze[i][j]==1){
cout<<" *";
}
else if(maze[i][j]==0){
cout<<" ";
}
else{
cout<<" #";
}
}
cout<<'\n';
}
cout<<" ====================\n";
}
point sp={1,0},ep={8,9};//记录起始点和终点的坐标
point prepts[MAXROW][MAXCOLUMN]={-1,-1};//用来记录当前坐标的前一个坐标
void printpath(){
stack<point> s1;//用栈先进后出的特点,从终点倒序将点压入栈,直到起点,然后弹栈
point temp=ep;
do{
s1.push(temp);
temp=prepts[temp.x][temp.y];
}while(!(temp.x==sp.x&&temp.y==sp.y));
s1.push(temp);
while(!s1.empty()){
temp=s1.top();
s1.pop();
cout<<"("<<temp.x<<", "<<temp.y<<") ";
}
cout<<'\n';
}
bool flag=0;
void dfs(point now){
maze[now.x][now.y]=2;
Sleep(500);
system("cls");
displayMaze();
if(now.x==ep.x&&now.y==ep.y){
cout<<"find the path!"<<endl;
flag=1;
return;
}
else{
for(int i=0;i<3;i++){
point nxt{now.x+dx[i],now.y+dy[i]};
if(maze[nxt.x][nxt.y]==0&&nxt.x>=0&&nxt.x<=MAXROW&&nxt.y>=0&&nxt.y<=MAXCOLUMN){
prepts[nxt.x][nxt.y]=now;//追踪最终路径肯定要从终点往前追踪,起点开始会有很多条路,不好区分
dfs(nxt);
}
}
}
}
int main()
{
dfs(sp);
if(flag)
printpath();
else
cout<<"fail to find the end!";
return 0;
}
实际运行效果
这个原理和八皇后类似,先从第一点开始递归下去上色,如果遇到颜色不够发生同色冲突时,再回溯,先前的点换个颜色后再继续递归,直到最后一个点被上色完成(最后一个上完后也会回溯,就是寻找另一种上色方法了)。但如何检测每个点是否与相邻的点的颜色相同呢,困扰了我挺久。后来想起邻接矩阵,用一个二维数组就可以表示清点与点之间的相邻关系了,再用一个数组去表示每个点的颜色就行了。
#include <iostream>
#include <string>
using namespace std;
const int m=4,n=5;//m:color,n:vertexes
int counts=0;//the count of number of methods of coloring each vertex
int adjMatrix[5][5]{
0 ,1 ,1 ,1 ,0 ,
1 ,0 ,1 ,1 ,1 ,
1 ,1 ,0 ,1 ,0 ,
1 ,1 ,1 ,0 ,1 ,
0 ,1 ,0 ,1 ,0
};
int color[n];//the color of each vertex
string colorDescribe[m]{"red","blue","yellow","green"};
//check whether the color of two adjacent vertexes is the same
//1:not the same
bool check(int x){
for(int i=0;i<x-1;i++)//i<x-1, no need to check vertexes that haven't been colored
if(adjMatrix[x-1][i]==1&&color[i]==color[x-1]) return 0;
return 1;
}
void colorGraph(int vertex){
//n+1,画到第六个点时说明前五个都上色成功
if(vertex==n+1){
counts++;
cout<<"Method "<<counts<<": ";
for(int i=0;i<n;i++)
cout<<"V"<<i+1<<": "<<colorDescribe[color[i]-1]<<", ";
cout<<endl;
return;
}
else{
for(int i=1;i<m+1;i++){
color[vertex-1]=i;
if(check(vertex)){
colorGraph(vertex+1);
}
color[vertex-1]=0;//当前点颜色清空,提供回溯条件
}
}
}
int main()
{
colorGraph(1);//从一号点开始
cout<<counts;
return 0;
}
代码用的是4个颜色,五个点的情况
大名鼎鼎的八皇后问题,每个皇后的横排竖排斜排都不能有其他皇后存在。这个方法与上色同理。先放好一个皇后,再去放第二个皇后,检测横排竖排斜排是否有其他皇后。如果递归到了死局,怎么放都会冲突,就回溯(当然到达了base case也会回溯,就是寻找下一种摆法了),改变先前的皇后位置,以新面貌继续进行递归。
检测那里出错了好久,我一开始傻了,只检测当前皇后的上面一行,或者一个斜格,后来想想就算第一个也会与第八个在一个斜线上,检测时应该是要考虑当前行数的。
#include <iostream>
using namespace std;
const int n=8;//8 queens
int board[n][n];//8x8 chessboard
int counts=0;//counts of methods
struct queen{
int x;
int y;
};
queen q[n];//the number of the queens
//Check whether has other queens on diagonal and vertical lines
//need to make sure the array index won't out of bounds
bool check(queen k){
for(int row=k.x;row>0;row--){
if(k.x>=0&&k.y>0&&k.y<n-1){
if(board[k.x-row][k.y]==1|| ( k.y-row>=0 && board[k.x-row][k.y-row]==1) || (k.y+row<=n-1 &&board[k.x-row][k.y+row]==1))
return 0;
}
else if(k.y==0){
if(board[k.x-row][k.y]==1 || (k.y+row<=n-1 && board[k.x-row][k.y+row]==1))
return 0;
}
else if(k.y==n-1){
if( board[k.x-row][k.y]==1 ||( k.y-row>=0 && board[k.x-row][k.y-row]==1))
return 0;
}
}
return 1;
}
//traceback
void n_queen(int row){
//base case: when reach the 9th row, one method is found,recursion stop
if(row==n+1){
counts+=1;
return;
}
else{
for(int col=0;col<n;col++){
q[row-1].x=row-1;
q[row-1].y=col;
board[row-1][col]=1;//1:this position has a queen
if(check(q[row-1])){
n_queen(row+1);
}
board[row-1][col]=0;
}
}
}
int main()
{
n_queen(1);//start from the first row
cout<<"For "<<n<<" queens, there are "<<counts<<" different methods to put.";
return 0;
}
8个的情况是92种,程序应该是没问题的。
原文:https://www.cnblogs.com/dreamyt/p/di-gui-hui-su-fa.html