马踏棋盘的实现

问题描述

设计一个国际象棋的马踏棋盘的演示程序

基本要求

将马放到国际象棋的8*8棋盘board上的某个方格中,马按走棋规则进行移动,要求每个方格只进入一次,走遍棋盘上的64个方格,编写递归程序,求出马的行走路线,并按求出路线,将数字12 3.。。。。64依次填入一个8*8的方阵,输出之

测试数据

初始位置由程序使用者指定,(i, j)   注:(0<=i<8)   (0<=j<8)


首先这是一个搜索问题,运用深度优先搜索进行求解。算法如下:
1、输入初始位置坐标x,y。
2、计算当前坐标的八个方位的子结点,选出那此可行的子结点。
   循环遍历所有可行子结点,重复2。
   如果所有节点都不可行,出栈,选取下一子节点,重复步骤2。
   显然步骤2是一个反复的过程,这样做是完全可行的,它输入的是全部解,但是马遍历当8×8时解是非常之多的,用天文数字形容也不为过,这样一来求解的过程就非常慢,并且出一个解也非常慢。怎么才能快速地得到部分解呢?
【贪心算法】
其实马踏棋盘的问题很早就有人提出,且早在1823年,J.C.Warnsdorff就提出了一个有名的算法。在每个结点对其子结点进行选取时,优先选择‘出口’最小的进行搜索,‘出口’的意思是在这些子结点中它们的可行子结点的个数,也就是‘孙子’结点越少的越优先跳,为什么要这样选取,这是一种局部调整最优的做法,如果优先选择出口多的子结点,那出口少的子结点就会越来越多,很可能出现‘死’结点(顾名思义就是没有出口又没有跳过的结点),这样对下面的搜索纯粹是徒劳,这样会浪费很多无用的时间,反过来如果每次都优先选择出口少的结点跳,那出口少的结点就会越来越少,这样跳成功的机会就更大一些。这种算法称为为贪心算法,也叫贪婪算法或启发示算法,它对整个求解过程的局部做最优调整,它只适用于求较优解或者部分解,而不能求最优解。这样的调整方法叫贪心策略,至于什么问题需要什么样的贪心策略是不确定的,具体问题具体分析。实验可以证明马遍历问题在运用到了上面的贪心策略之后求解速率有非常明显的提高,如果只要求出一个解甚至不用回溯就可以完成,

在前面的算法基础之上,增添一些程序加以实现:





以下附代码

/*
 * =====================================================================================
 *
 *       Filename:  horse.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  2013年09月13日 22时39分47秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  gaoyuan, 
 *        Company:  Class 1204 of Computer Science and Technology
 *
 * =====================================================================================
 */

#include <unistd.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 100
#define STACKINCREASE 10
#define N   8
#define TRUE   1
#define FALSE  0


int i_i, j_j;
int tmp_p[N][N] = {0};
typedef struct chess
{
	int x;
	int y;
	int dir_choose;
	int flag;
//	int dir[8];
}CHESS;

int map[N][N][8];   //存放下一步方向
int board[N][N][8];  
int weight[N][N];
CHESS choose[8] = {{-2, 1, 0}, {-1, 2, 0}, {1, 2, 0}, {2, 1, 0}, {2, -1, 0}, {1, -2, 0}, {-1, -2, 0}, {-2, -1, 0}};

typedef struct SeqStack
{
	CHESS *base;
	CHESS *top;
	int size;      //已用空间
	int len;
}SqStack;

void init_Stack(SqStack *s)
{
	s->base = (CHESS *)malloc(MAXSIZE * sizeof(CHESS));

	if (!s->base)
	{
		printf("失败\n");
		exit (0);
	}
	s->top = s->base;
	s->size = MAXSIZE;
	s->len = 0;
}

int if_empty(SqStack *s)
{
	if (s->len == 0)
	{
		return TRUE;
	}

	else
	{
		return FALSE;
	}
}

int top_stack(SqStack *s, CHESS *p)
{
	if (s->top > s->base)    //如果栈非空
	{
		*p = *(s->top - 1);
		return TRUE;
	}

	else
	{
		return FALSE;
	}
}

int change_stack(SqStack *s, CHESS *p, int x, int y, int z)   //待定
{
	int k;

	if (s->top > s->base)
	{
		p->dir_choose = board[x][y][z + 1];
		p->flag = z + 1;
		*(s->top - 1) = *p;
		return TRUE;
	}

	else
	{
		return FALSE;
	}
}

int push_stack(SqStack *s, CHESS *p)
{
	if (s->top - s->base == s->size)
	{
		s->base = (CHESS *)realloc(s->base, (s->size + STACKINCREASE) * sizeof(CHESS));
		s->top = s->base + s->size;
		s->size += STACKINCREASE;
	}

	*s->top = *p;
	s->top++;
	s->len++;
	

	return TRUE;
}

int pop_stack(SqStack *s, CHESS *p)
{
	if ((*s).base == (*s).top)
	{
		return FALSE;
	}

	*p = *(s->top - 1);
	s->top--;
	s->len--;
}

void setweight()
{
	int i, j, k;
	int x, y;

	for (i = 0; i < N; i++)
	{
		for (j = 0; j < N; j++)
		{
			weight[i][j] = 0;
			for (k = 0; k < 8; k++)
			{
				x = choose[k].x + i;
				y = choose[k].y + j;

				if (x >= 0 && x < N && y >= 0 && y < N)
				{
					weight[i][j]++;     //当前位置有多少方向可以移动

				}
			}
		}
	}
}

int check(int x, int y)
{
	if (x < 0 || x >= N || y < 0 || y >= N)
	{
		return 0;
	}

	return 1;
}

void setmap()
{
	int a[8];
	int i, j, k, m, min, s, h;
	int b;

	CHESS n1, n2;

	for (i = 0; i < N; i++)
	{
		for (j = 0; j < N; j++)
		{
			for (h = 0; h < 8; h++)
			{
				n1.x = i;
				n1.y = j;

				n2.x = i + choose[h].x;
				n2.y = j + choose[h].y;

				if (check(n2.x, n2.y) != 0)
				{
					map[i][j][h] = weight[n2.x][n2.y];
					board[i][j][h] = h;
				}

				else
				{
					map[i][j][h] = 9;
					board[i][j][h] = 9;
				}
			}
				for (m = 0; m < 7;m++)
				{
					
					for (k = m + 1; k < 8; k++)
					{
						if (map[i][j][m] > map[i][j][k])
						{
							min = map[i][j][m];
							map[i][j][m] = map[i][j][k];
							map[i][j][k] = min;
							min = board[i][j][m];
							board[i][j][m] = board[i][j][k];
							board[i][j][k] = min;
						}
					}
		//			printf("%d\t", map[i][j][m]);
				}
				printf("\n");
			}
		}

	getchar();
}

void show(int a[][N], int x, int y)
{
	int i, j;

	for (i = 0; i < x; i++)
	{
		for (j = 0; j < y; j++)
		{
			printf("%5d", a[i][j]);
		}
		printf("\n");
	}
}
void path(int x, int y)
{
	int tmp_x, tmp_y, tmp_flag, flag;
	int a[N * N] = {0}, b[N * N] = {0};
	SqStack s;
	int num = 0;
	int i = 0;

	init_Stack(&s);
	
	CHESS local;
	CHESS next_step;

	local.x = x;
	local.y = y;
	local.dir_choose = board[x][y][0];
	local.flag = 0;

	tmp_p[x][y] = num + 1;
	push_stack(&s, &local);
	while (1)
	{
	if (if_empty(&s) == TRUE)
		{
			break;
		}
		top_stack(&s, &local);
		tmp_x = local.x;
		tmp_y = local.y;
		tmp_p[tmp_x][tmp_y] = num+1;
		tmp_flag = local.dir_choose;
		flag = local.flag;
	if (num == (N * N - 1))
		{
			printf("%d   end\n", if_empty(&s));
			break;
		}
		
		show(tmp_p, N, N);
		sleep(0.5);
		system("clear");
	//	getchar();
		if (flag >= weight[tmp_x][tmp_y])   //所有方向已经走完
		{
			tmp_p[tmp_x][tmp_y] = 0;
			pop_stack(&s, &local);
			top_stack(&s, &local);
			flag = local.flag ;
			num--;
			change_stack(&s, &local, local.x, local.y, flag);
		}
		else if (flag < weight[tmp_x][tmp_y])
		{
			next_step.x = tmp_x + choose[tmp_flag].x;
			next_step.y = tmp_y + choose[tmp_flag].y;
			if (check(next_step.x, next_step.y) && tmp_p[next_step.x][next_step.y] == 0)
			{
				num++;
				flag = 0;
				next_step.dir_choose = board[next_step.x][next_step.y][flag];
				next_step.flag = 0;
				push_stack(&s, &next_step);
			}
			else
			{
				change_stack(&s, &local, tmp_x, tmp_y, flag);
				flag++;
			}
		}
	}
	show(tmp_p, N, N);
}

int main(int argc, char *argv[])
{
	int x, y;
	int i, j, m;
	SqStack p;
	init_Stack(&p);


	for (i = 0; i < N; i++)
	{
		for(j = 0; j < N; j++)
		{
			weight[i][j] = 0;
			for (m = 0;m < N; m++)
		  	board[i][j][m] = 0;
	  	}
	}
	
	printf("请输入马起始的x坐标:");
	scanf("%d", &x);
	printf("请输入马起始的y坐标:");
	scanf("%d", &y);

	if (check(x, y) < 0)
	{
		printf("输入错误,请重新键入\n");
		return 0;
	}

	setweight();

	for (i = 0;i < N; i++)
	{
		for (j = 0;j < N; j++)
		{
			printf("%5d", weight[i][j]);
		}
		printf("\n");
	}
//	getchar();
//	getchar();


	setmap();


	path(x, y);







	return EXIT_SUCCESS;

}


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yancygao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值