|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 Vision 于 2023-11-30 06:22 编辑
马踏棋盘问题(又称骑士周游或骑士漫游问题)是算法设计的经典问题之一。
国际象棋的棋盘为8*8的方格棋盘,现将“马”放在任意指定的方格中,按照“马走日”的规则将“马”进行移动,要求每个方格只能进入一次,最终使得“马”走遍棋盘64个方格。
题目:编写代码,实现马踏棋盘的操作,要求使用 1~64 来标注“马”移动的轨迹。
#include <stdio.h>
#include <time.h>
#define N 8 //国际象棋8行8列
#define POSITIONS 8 //国际象棋中马最多可以走八个位置
int GetNextPosition(int, int, int PositionsList[N][N][POSITIONS*2+2], const int ChessBoard[N][N]);
int sort(int row, int col, int PositionsList[N][N][POSITIONS*2+2], const int ChessBoard[N][N]);
int HorseWalkOverChessBoard(int, int, int ChessBoard[N][N]);
int main()
{
int row, column, ChessBoard[N][N] = {0};
time_t StartTime, EndTime;
printf("请输入第一步棋的行和列(1-%d):", N);
scanf("%d%d", &row, &column);getchar();
putchar('\n');
row--, column--;
StartTime = time(NULL);
if(HorseWalkOverChessBoard(row, column, ChessBoard))
{
for(row = 0; row < N; row++)
{
for(column = 0; column < N; column++)
printf("%4d", ChessBoard[row][column]);
printf("\n\n");
}
printf("成功! ");
}
else
printf("迷路了! ");
printf("用时%d分%d秒。\n\n", ((EndTime=time(NULL))-StartTime)/60, (EndTime-StartTime)%60);
return 0;
}
int HorseWalkOverChessBoard(int row, int col, int ChessBoard[N][N])
{
int PositionsList[N][N][POSITIONS*2+2] = {0}, path[N*N*2];
int CanToPoints, NewRow, NewCol, step = 0;
int *PathPoint = &path[0];
CanToPoints = GetNextPosition(row, col, PositionsList, ChessBoard);
sort(row, col, PositionsList, ChessBoard);
ChessBoard[row][col] = 1;
*PathPoint = row, *(PathPoint+1) = col;
PathPoint += 2, step++;
while(step < N*N)
{
if(PositionsList[row][col][POSITIONS*2] < PositionsList[row][col][POSITIONS*2+1])
{
NewRow = PositionsList[row][col][PositionsList[row][col][POSITIONS*2]];
NewCol = PositionsList[row][col][PositionsList[row][col][POSITIONS*2] + 1];
PositionsList[row][col][POSITIONS*2] += 2;
row = NewRow, col = NewCol;
CanToPoints = GetNextPosition(row, col, PositionsList, ChessBoard);
sort(row, col, PositionsList, ChessBoard);
if(step == N*N-1 && !ChessBoard[row][col]) CanToPoints = 2;//最后一步不能预判,特别处理
if(CanToPoints) //预判该棋格是否可行,减少回溯次数。
{
*PathPoint++ = row, *PathPoint++ = col; //移动轨迹
ChessBoard[row][col] = ++step; //在棋格标记步数
}
}
else
{
--step, PathPoint -= 2;
if(PathPoint < path) return 0;
ChessBoard[*PathPoint][*(PathPoint+1)] = 0; //当前棋格无路可走则删除数据
row = *(PathPoint-2), col = *(PathPoint-1); //回溯上一棋格
}
}
return 1;
}
int GetNextPosition(int row, int col, int p[N][N][POSITIONS*2+2], const int ChessBoard[N][N])
{
int i = 0;
if(!ChessBoard[row+1][col-2] && row+1 < N && col-2 >= 0) p[row][col][i++] = row+1, p[row][col][i++] = col-2;//左下
if(!ChessBoard[row-1][col-2] && row-1 >= 0 && col-2 >= 0) p[row][col][i++] = row-1, p[row][col][i++] = col-2;//左上
if(!ChessBoard[row+1][col+2] && row+1 < N && col+2 < N) p[row][col][i++] = row+1, p[row][col][i++] = col+2;//右下
if(!ChessBoard[row-1][col+2] && row-1 >= 0 && col+2 < N) p[row][col][i++] = row-1, p[row][col][i++] = col+2;//右上
if(!ChessBoard[row-2][col-1] && row-2 >= 0 && col-1 >= 0) p[row][col][i++] = row-2, p[row][col][i++] = col-1;//上左
if(!ChessBoard[row-2][col+1] && row-2 >= 0 && col+1 < N) p[row][col][i++] = row-2, p[row][col][i++] = col+1;//上右
if(!ChessBoard[row+2][col-1] && row+2 < N && col-1 >= 0) p[row][col][i++] = row+2, p[row][col][i++] = col-1;//下左
if(!ChessBoard[row+2][col+1] && row+2 < N && col+1 < N) p[row][col][i++] = row+2, p[row][col][i++] = col+1;//下右
p[row][col][POSITIONS*2] = 0; //p[POSITIONS*2]用于保存指针
p[row][col][POSITIONS*2+1] = i; //p[POSITIONS*2+1]保存可到达位置个数
return p[row][col][POSITIONS*2+1];
}
int sort(int row, int col, int PositionsList[N][N][POSITIONS*2+2], const int ChessBoard[N][N])
{
int i, j, k, r, c, arr[POSITIONS] = {0};
if(PositionsList[row][col][POSITIONS*2+1] < 2)
return PositionsList[row][col][POSITIONS*2+1];
for(i = 0; i < PositionsList[row][col][POSITIONS*2+1]; i += 2)
{
j = PositionsList[row][col][i], k = PositionsList[row][col][i+1];
arr[i/2] = GetNextPosition(j, k, PositionsList, ChessBoard);
}
for(i = 1; i < PositionsList[row][col][POSITIONS*2+1]/2; i++) //插入排序
{
r = PositionsList[row][col][i*2];
c = PositionsList[row][col][i*2+1];
k = arr[i];
j = i - 1;
while((j >= 0) && (arr[j] > k))
{
arr[j+1] = arr[j];
PositionsList[row][col][2*(j+1)+1] = PositionsList[row][col][2*j+1];
PositionsList[row][col][2*(j+1)] = PositionsList[row][col][2*j];
j--;
}
arr[j+1] = k;
PositionsList[row][col][2*(j+1)+1] = c;
PositionsList[row][col][2*(j+1)] = r;
}
return PositionsList[row][col][POSITIONS*2+1];
}
运行效果:
请输入第一步棋的行和列(1-8):4 3
12 43 14 33 10 39 48 31
15 34 11 42 47 32 9 40
44 13 52 35 38 41 30 49
53 16 1 46 59 50 37 8
2 45 58 51 36 25 60 29
17 54 19 26 57 64 7 24
20 3 56 63 22 5 28 61
55 18 21 4 27 62 23 6
成功! 用时0分0秒。
请按任意键继续. . . |
|