64,642
社区成员
发帖
与我相关
我的任务
分享
#include<stdio.h>
int H[8][8] = {0}; // 全局变量的二维数组,用以保存马走步的放置情况
// 其中每个元素存放走步的序号,初值为 0
int P[8][8] = {0}; // 全局变量的二维数组,对应于棋盘上各个位置可以
// 选择的位置数,即邻接点的度
bool g_find_solution = false; // 标示是否找到了走法
// 位于[x,y]位置的马,需要检测 8 个方向来确定下一个位置, 如下图:
//
// 2 3 方向1: [x-1,y-2]; 方向2: [x-2,y-1];
// 1 4 方向3: [x-2,y+1]; 方向4: [x-1,y+2];
// H<---------[x,y] 方向5: [x+1,y+2]; 方向6: [x+2,y+1];
// 8 5 方向7: [x+2,y-1]; 方向8: [x+1,y-2];
// 7 6 注:x 为行,y 为列,探测方向:1-8
struct D { // 通过结构体来定义 8 个方向
int x;
int y;
}DIR[8] = {
{-1,-2}, {-2,-1}, {-2,1}, {-1,2}, // 方向:1,2,3,4
{1,2}, {2,1}, {2,-1}, {1,-2} // 方向:5,6,7,8
};
void InitP(int initX, int initY) // 填充棋盘上每个位置的选择度数
{
int i,j,k; // 临时变量
int u,v; // 保存探测位置的坐标
for (i=0; i<8; i++) { // 行递增
for(j=0; j<8; j++) { // 列递增
for(k=0; k<8; k++) { // 探测 8 个方向
u = i + DIR[k].x;
v = j + DIR[k].y;
if( (u >= 0) && (u < 8) && // 行方向合法性判断
(v >= 0) && (v < 8) ) { // 列方向合法性判断
P[i][j] ++; // 位置的度数加 1
}
}
}
}
P[initX][initY] = 0; // 将初始位置的选择度数置为 0
}
void go(int x,int y,int i) // 搜索第 i 步的位置
{
int j,m,n; // 临时变量
int min; // 保存最小临接度数
int u,v; // 保存探测位置坐标
int u1 = -1,v1 = -1; // 保存有最小临接度数的位置坐标
if(i == 65) { //递归出口,若棋盘上的每个位置都走过一遍,则算法结束
g_find_solution = true;
for(m = 0;m < 8;m++) {
printf("\n");
for(n = 0;n < 8;n++)
printf("%5d",H[m][n]);
}
printf("\n\n");
}
else { // 每一步都探测 8 个方向来确定下一个位置
min = 8; // 初始最小临接度数为最大值 8
for(j = 0;j < 8;j++) { // 遍历 8 个方向寻找有最小临接度数位置
u = x + DIR[j].x; // 第 j 个方向的行坐标
v = y + DIR[j].y; // 第 j 个方向的列坐标
if( (u >= 0) && (u < 8) && // 行方向合法性判断
(v >= 0) && (v < 8) && // 列方向合法性判断
(H[u][v] == 0) ) { // 是否可走判断
P[u][v] --; // 其邻接点的度减 1
if(P[u][v] < min) {
min = P[u][v];
u1 = u; // 保存有最小临接度数位置的行坐标
v1 = v; // 保存有最小临接度数位置的列坐标
}
}
}
if(u1 == -1 || v1 == -1) { // 8 个方向都不满足,周游搜索失败
return;
}
H[u1][v1] = i; // 用有最小临接度数位置坐标设置当前的步序号
go(u1,v1,i+1); // 并将其作为下一步的起点,继续递归调用
}
}
int main(void)
{
int m,n;
printf("**********马的周游路线*********");
printf("说明:以下面的模拟棋盘为例:\n");
for(m = 0;m < 8;m++) {
printf("\n");
for(n = 0;n < 8;n++)
printf("%d%d ",m,n);
}
printf("\n\n请输入马的当前位置,格式:x,y (其中 0=<x<8, 0=<y<8):");
scanf("%d,%d",&m,&n);
while (m<0 || m>8 || n<0 || n>8)
{
printf("\n\n你的输入有误!");
printf("\n\n请输入马的当前位置,格式:x,y (其中 0=<x<8, 0=<y<8):");
scanf("%d,%d",&m,&n);
}
printf("\n");
H[m][n] = 1;
InitP(m,n);
go(m,n,2);
printf("\n");
if (!g_find_solution) {
printf("\n\n从输入点 (%d, %d) 开始,没有找到可行的路径!", m, n);
}
return 0;
}
// 输出结果:
/*
**********马的周游路线*********说明:以下面的模拟棋盘为例:
00 01 02 03 04 05 06 07
10 11 12 13 14 15 16 17
20 21 22 23 24 25 26 27
30 31 32 33 34 35 36 37
40 41 42 43 44 45 46 47
50 51 52 53 54 55 56 57
60 61 62 63 64 65 66 67
70 71 72 73 74 75 76 77
请输入马的当前位置,格式:x,y (其中 0=<x<8, 0=<y<8):1,2
2 23 4 19 44 39 14 17
5 20 1 40 15 18 45 38
24 3 22 43 52 47 16 13
21 6 59 48 41 50 37 46
62 25 42 51 60 53 12 33
7 28 61 58 49 34 55 36
26 63 30 9 54 57 32 11
29 8 27 64 31 10 35 56
请按任意键继续. . .
*/
printf("**********马得周游路线*********"); // 应该改为:
printf("**********马的周游路线*********");
printf("\n\n请输入马得当前位置,格式:x,y (其中 0=<x<%d, 0=<y<%d):",R,C); // 改为:
printf("\n\n请输入马的当前位置,格式:x,y (其中 0=<x<%d, 0=<y<%d):",R,C);
#include<stdio.h>
// 注: 当为 8*8 的棋盘时,运行非常慢,在我电脑上要将近10分钟
// 可以用较小的数据测试,如 7*7 ,6*6 或 6*7等
#define R 8 // 棋盘的行数
#define C 8 // 棋盘的列数
#define N (R*C+1) // 最大序号+1
int H[R][C] = {0}; // 全局变量的二维数组,用以保存马走步的放置情况
// 其中每个元素存放走步的序号,初值为0
bool g_just_find_one = false; // 标示是否只找一个走法,还是所有的
bool g_find_solution = false; // 标示是否找到了走法
// 位于[x,y]位置的马,需要检测 8 个方向来确定下一个位置, 如下图:
//
// 2 3 方向1: [x-1,y-2]; 方向2: [x-2,y-1];
// 1 4 方向3: [x-2,y+1]; 方向4: [x-1,y+2];
// H<---------[x,y] 方向5: [x+1,y+2]; 方向6: [x+2,y+1];
// 8 5 方向7: [x+2,y-1]; 方向8: [x+1,y-2];
// 7 6 注:x 为行,y 为列,探测方向:1-8
struct D { // 通过结构体来定义 8 个方向
int x;
int y;
}DIR[8] = {
{-1,-2}, {-2,-1}, {-2,1}, {-1,2}, // 方向:1,2,3,4
{1,2}, {2,1}, {2,-1}, {1,-2} // 方向:5,6,7,8
};
void go(int x,int y,int i) { // 搜索第 i 步的位置
int j,u,v,m,n;
if (g_just_find_one) { // 如果只找一个走法
if(g_find_solution) {
return;
}
}
if(i == N) { // 递归出口,若棋盘上的每个位置都走过一遍,则算法结束
g_find_solution = true;
for(m = 0;m < R;m++) {
printf("\n");
for(n = 0;n < C;n++)
printf("%5d",H[m][n]);
}
printf("\n\n\n");
}
else { // 每一步都探测8个方向来确定下一个位置
for(j = 0;j < 8;j++) {
u = x + DIR[j].x;
v = y + DIR[j].y;
if( (u >= 0) && (u < R) && // 行方向合法性判断
(v >= 0) && (v < C) && // 列方向合法性判断
(H[u][v] == 0) ) { // 是否可走判断
H[u][v] = i; // 位置合法,将该位置设置为当前步的序号
go(u,v,i+1); // 从当前位置走下一步
H[u][v] = 0; // 上一个方向探测结束后,将探测过的位置复位
// 以进行下一个方向的探测
}
}
}
}
int main(void) {
int m,n;
char ch;
printf("**********马得周游路线*********");
printf("说明:以下面的模拟棋盘为例:\n");
for(m = 0;m < R;m++) {
printf("\n");
for(n = 0;n < C;n++)
printf("%d%d ",m,n);
}
printf("\n\n请输入马的当前位置,格式:x,y (其中 0=<x<%d, 0=<y<%d):",R,C);
scanf("%d,%d",&m,&n);
while (m<0 || m>R || n<0 || n>C)
{
printf("\n\n你的输入有误!");
printf("\n\n请输入马得当前位置,格式:x,y (其中 0=<x<%d, 0=<y<%d):",R,C);
scanf("%d,%d",&m,&n);
}
getchar();
printf("\n\n是否只要求一个解法(Y 或 y 表示是,其它键表示否):");
scanf("%c",&ch);
if (ch == 'Y' || ch == 'y') {
g_just_find_one = true;
}
printf("\n");
H[m][n] = 1;
go(m,n,2);
printf("\n");
if (!g_find_solution) {
printf("\n\n从输入点 (%d, %d) 开始,没有可行的路径!", m, n);
}
return 0;
}
// 输出示例:
/*
**********马得周游路线*********说明:以下面的模拟棋盘为例:
00 01 02 03 04 05 06 07
10 11 12 13 14 15 16 17
20 21 22 23 24 25 26 27
30 31 32 33 34 35 36 37
40 41 42 43 44 45 46 47
50 51 52 53 54 55 56 57
60 61 62 63 64 65 66 67
70 71 72 73 74 75 76 77
请输入马的当前位置,格式:x,y (其中 0=<x<8, 0=<y<8):2,0
是否只要求一个解法(Y 或 y 表示是,其它键表示否):y
9 2 11 16 25 4 13 64
18 21 8 3 12 15 26 5
1 10 17 20 7 24 63 14
42 19 22 55 50 61 6 27
57 54 43 34 23 36 49 62
44 41 56 51 60 33 28 31
53 58 39 46 35 30 37 48
40 45 52 59 38 47 32 29
请按任意键继续. . .
*/