算法设计与分析:第五章 回溯法 5.5马的遍历

/*
马的遍历问题:
在n*m的棋盘中,马只能走“日” 字。马从位置(x,y)处出发,把棋盘的每一格都走一次,
且只走一次。找出所有路径。

问题分析:
1问题解的搜索空间?
棋盘的规模是n*m,是指行有n条边,列有m条边
马在棋盘的点上走,所以搜索控件是整个棋盘上的n*m个点
用n*m的二维数组记录马行走的过程,初值为0标识未经过。

2在寻找路径过程中,活结点的扩展规则?
对于棋盘上任意一点A(x,y),有8个扩展方向:
A(x+1,y+2),A(x+1,y-2)
A(x+2,y+1),A(x+2,y-1)
A(x-1,y-2),A(x-1,y+2)
A(x-2,y-1),A(x-2,y+1)
用数组fx[8] = {1,1,2,2,-1,-1,-2,-2},
fy[8]={2,-2,1,-1,-2,2,-1,1}来模拟马走日时下表的变化过程

问题3:扩展的约束条件?
1)不出边界
2)每个点只经过一次
棋盘点对应的数组元素初值为0,对走过的棋盘点的值置为所有步数
起点存储1,重点存储n*m

函数check,检查当前状态是否合理

问题4:搜索解空间?
搜索过程是从任一点(x,y)出发,按照深度优先原则,从8个方向
尝试一个可以走的棋盘点,直到走过棋盘上所有n*m个点。递归算法

注意要求找出全部可能的解,注意回溯过程的清理现场工作,也就是
置当前位置为未经过

数据结构设计:
1)用一个变量dep记录递归深度=走过的点数,当dep=n*m时,找到一族解
2)用n*m的二维数组记录马行走的过程,初始值为0标识未经过。搜索完毕后,
起点存储的是1,终点存储的是n*m

输入:
10 9
4 4
输出:

//未解决
*/
#include <stdio.h>
#include <string.h>

const int MAXSIZE = 100;
int g_count;
//方向数组
//int g_x[8] = {1,1,2,2,-1,-1,-2,-2};
//int g_y[8] = {2,-2,1,-1,-2,2,-1,1};
int g_x[8]={1,2,2,1,-1,-2,-2,-1};
int g_y[8]= {2,1,-1,-2,-2,-1,1,2}; 
//记录所走的顺序
int g_path[MAXSIZE][MAXSIZE];

void print(int n,int m)
{
	g_count++;
	for(int i = 0 ; i < n ; i++)
	{
		for(int j = 0 ; j < m ; j++)
		{
			printf("%d ",g_path[i][j]);
		}
		printf("\n");
	}
	printf("\n");
}

//已经拥有深度,同时兼顾了计数的功能,因此,无需再进行计数
void dfs(int x,int y,int iDepth,int n,int m)
{
	int xx,yy;
	//迷宫算法典型步骤,一上来就是方向的扩展
	for(int i = 0 ; i < 8 ; i++)
	{
		//获取新方向
		xx = x + g_x[i];
		yy = y + g_y[i];
		//剪枝:是否越界
		if(xx < 0 || xx >= n || yy < 0 || yy >= m)
		{
			continue;
		}
		//剪枝:是否访问过
		if(g_path[xx][yy] != 0)
		{
			continue;
		}
		//设定新方向的存储值
		g_path[xx][yy] = iDepth;
		//判断是否达到递归出口
		if(iDepth == n*m)
		{
			//return ;
			//注意,这里要走出所有路径,因此不能返回,而是输出
			print(n,m);
		}
		//如果没有到达递归出口
		else
		{
			//递归
			dfs(xx,yy,iDepth+1,n,m);
			//置已访问标记为未访问
			//g_path[xx][yy] = 0;
		}
	}
	//置已访问标记为未访问
	g_path[xx][yy] = 0;
	//iDepth--;
}



void process()
{
	int n,m;
	while(EOF != scanf("%d %d",&n,&m))
	{
		//让用户输入想走的位置
		//int ix = 0;
		//int iy = 0;
		//scanf("%d %d",&ix,&iy);
		for(int ix = 0 ; ix < n ; ix++)
		{
			for(int iy = 0 ; iy < m ; iy++)
			{
				g_count = 0;
				//关键,初始深度为1,所以调用的时候从第二个节点开始走,因此赋予深度为2
				int iDepth = 2;
				memset(g_path,0,sizeof(g_path));
				//设定初始节点记录值为1
				g_path[ix][iy] = 1;
				dfs(ix,iy,iDepth,n,m);
				//print(n,m);
				if(g_count == 0)
				{
					printf("x=%d,y=%d,没有答案\n",ix,iy);
				}
				else
				{
					printf("x=%d,y=%d,答案个数为:%d\n",ix,iy,g_count);
				}
			}
		}
	}
}

int main(int argc,char* argv[])
{
	process();
	getchar();
	return 0;
}

//#include <stdio.h>
//#include <iostream>
//#include <stdlib.h>
//
//using namespace std;
//const int n=10;
//const int m=9;
//int a[n][m];
//int dep;
//
//int g_count;
//
//int fx[8]={1,2,2,1,-1,-2,-2,-1};
//int fy[8]={2,1,-1,-2,-2,-1,1,2};
//
//void output()
//{ 
//	g_count= g_count+1;
//	cout << endl;
//	cout << "count =" << g_count << endl;
//	for (int x=1;x<=n;x++)
//	{ 
//		for(int y=1;y<=m;y++)
//		{
//			cout << a[x][y] << "\t";
//		}
//		cout << endl;
//	}
//}
//
//bool check(int xx,int yy)
//{
//	if(yy >n ||  xx >m || xx < 1 || yy <1)
//	{
//		return false;
//	}
//	if(a[xx][yy] != 0)
//	{
//		return false;
//	}
//	return true;
//}
//
//void find(int x,int y,int dep)
//{ 
//	int xx,yy;
//	for (int i=1;i<=8;i++) //加上方向增量,形成新的坐标
//	{ 
//		xx = x + fx[i];
//		yy = y + fy[i];
//		if (check(xx,yy)) //判断新坐标是否出界,是否已走过
//		{ 
//			a[xx][yy] = dep; //走向新的坐标
//			if (dep == n*m) 
//			{
//				output();
//			}
//			else
//			{
//				find(xx,yy,dep+1); //从新坐标出发,递归下一层
//			}
//		}
//	}
//	a[xx][yy]=0; //回溯,恢复未走标志
//}
//
//int main(int argc,char* argv[])
//{ 
//	int count=0; 
//	dep=1;
//	printf("input x,y\n");
//	//int x,y;
//	//while(cin >> x >> y)
//	//{
//	for(int x = 1 ; x <= n ; x++)
//	{
//		for(int y = 1 ; y <= m ;y++)
//		{
//			if (x > n ||  y > m || x < 1 || y < 1)
//			{ 
//				cout << "无效的输入" << endl;
//				return 0;
//			}
//			memset(a,0,sizeof(a));
//			a[x][y]=1;
//			find(x,y,2);
//			if (count ==0 )
//			{
//				cout << "x = " << x << ",y = ," << y << "No answer" << endl;
//			}
//			else 
//			{
//				cout << "x = " << x << ",y = ," << y << "count=" << count << endl;
//			}
//		}
//	}
//
//	//}
//	getchar();
//	system("pause");
//	return 0;
//}

    原文作者:回溯法
    原文地址: https://blog.csdn.net/qingyuanluofeng/article/details/47189427
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞