数据结构——马踏棋盘题解(贪心算法)
马踏棋盘问题是一个很经典的问题
一般的解决方法就是dfs,但是由于每次踏的方向不同,和初始值的不同,可能会增加这个问题的复杂的,所以在这里我们采用一些贪心算法,加权值进行优化
使用循环建立棋盘与权值棋盘(权值为该位置可走的位置数量)
将当前步数写入棋盘数组中
开始探测下一步该走的位置, 分别测试八个方向
对可走位置进行查询权值,将权值最少的作为下一步的位置(每次都将步数最少的可走位置作为下一步的位置即贪心的体现)[走最小的是因为棋盘的每个位置理论上都要便利一次,而走先走权值小的在走大的可以在一定程度上减小复杂的]
循环2~4。
代码实现 (基于C语言)首先给出基本的dfs代码
#include<stdio.h>
int cnt=0;
int map[12][12] = {0};
bool flag=false;
int vis[12][12] = {0};
int move[8][2] = { {2,1}, {1,2},{-1,2},{-2,1},{-2,-1},{-1,-2},{1, -2}, {2,-1}};
void dfs(int m, int n)
{
//i//f(flag)
//return ;
cnt++;
map[m][n]=cnt;
int i,j,k;
if(cnt==64)
{
//flag=true;
for(i=1;i<=8;i++)
{
for(j=1;j<=8;j++)
{
printf("%d ",map[i][j]);
}
printf("\n");
}
return ;
}
for(i = 0; i < 8; i++)
{
int xx = m + move[i][0];
int yy = n + move[i][1];
if(map[xx][yy]||xx<1||xx>8||yy<1||yy>8)
{
continue;
}
dfs(xx,yy);
map[xx][yy]=0;
cnt--;
}
}
int main(void)
{
int m,n,i,j;
scanf("%d %d", &m, &n);
for(i = 1;i<=m;i++)
{
for(j = 1 ;j <= n; j++)
{
int sum=0;
for(int k=0;k<8;k++)
{
int xx=i+move[k][0];
int yy =j+move[k][1];
if(xx>=1&&xx<=8&&yy>=1&&yy<=8)
{
sum++;
}
}
vis[i][j]=sum;
}
}
dfs(m,n);
return 0;
}
这个方法是直接dfs最多可能有8的8次方情况,是很复杂的,所以在此基础上,我们先遍历一遍进行加权值
代码实现如下
for(i=1;i<=8;i++)
{
for(j=1;j<=8;j++)
{
int k,sum=0;
for(k=1;k<=8;k++)
{
int xx=i+mo[k][0],yy=j+mo[k][1];
if(xx<1||yy<1||xx>8||yy>8)
continue;
sum++;
}
vis[i][j]=sum;
}
}
然后在写一个比较函数就是比较那个位置的权值小
for(int dir=1;dir<=8;dir++){ //探测下一步可走的方向
int x1=x+direction[0][dir];
int y1=y+direction[1][dir];
if(x1>=0&&x1<=7&&y1>=0&&y1<=7&&pow[x1][y1]!=9)
{
if(pow_min>pow[x1][y1]) //找出下一步位置中权值最小的
{
pow_min=pow[x1][y1];
t.d=dir; //上一步的方向
t.x=x1;
t.y=y1;
}
}
}
完整代码
//马踏棋盘—贪心题解
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define TRUE 1
#define ERROR 0
#define FALSE 0
#define M 8
#define N 8
int direction[2][9]={{0,-2,-1,1,2,2,1,-1,-2},{0,1,2,2,1,-1,-2,-2,-1}}; //增量数组
int pow[M][N];
int check[M][N],next[M][N]; //创建棋盘,初始为0
struct Element //数据域
{
int x,y; //x行,y列
int d; //下一步的方向
};
typedef struct LStack //链栈
{
Element data;
struct LStack *next;
}*PLStack;
typedef struct check //定义棋盘内点的坐标
{
int x;
int y;
}Check;
/*************栈函数****************/
int InitStack(PLStack &S)//构造空栈
{
S=NULL;
return OK;
}
int StackEmpty(PLStack S)//判断栈是否为空
{
if(S==NULL)
return OK;
else
return FALSE;
}
int Push(PLStack &S, Element e)//元素入栈
{
PLStack p;
p=(PLStack)malloc(sizeof(LStack));
p->data=e;
p->next=S;
S=p;
return OK;
}
int Pop(PLStack &S,Element &e) //元素出栈
{
PLStack p;
if(!StackEmpty(S))
{
e=S->data;
p=S;
S=S->next;
free(p);
return OK;
}
else
return FALSE;
}
/********贪心权值函数********/
void Printf(int p[M][N]){ //打印权值数组
for(int i=0;i<M;i++){
for(int j=0;j<N;j++)
printf(" %2d ",p[i][j]);
printf("\n");
}
}
void InitWeight(){ //创建权值数组并初始化每个位置的权值
for(int i=0;i<M;i++)
for(int j=0;j<N;j++)
pow[i][j]=0;
for(int i=0;i<M;i++){
for(int j=0;j<N;j++){
for(int dir=1;dir<=8;dir++){
int x1=i+direction[0][dir];
int y1=j+direction[1][dir];
if(x1>=0&&x1<=7&&y1>=0&&y1<=7)
pow[i][j]++;
}
}
}
}
void SetWeight(int x,int y) { //位置(x,y)设置为 被占用 时,修改权值数组 ,被占用时为9
pow[x][y]=9;
for(int dir=1;dir<=8;dir++){
int x1=x+direction[0][dir];
int y1=y+direction[1][dir];
if(x1>=0&&x1<=7&&y1>=0&&y1<=7&&pow[x1][y1]!=9)
pow[x1][y1]--;
}
}
void UnSetWeight(int x,int y){ //位置(x,y)设置为 未占用 时,修改权值数组
for(int dir=1;dir<=8;dir++){
int x1=x+direction[0][dir];
int y1=y+direction[1][dir];
if(x1>=0&&x1<=7&&y1>=0&&y1<=7&&pow[x1][y1]!=9){
pow[x1][y1]++;
pow[x][y]++;
}
}
}
/*******马踏棋盘函数*******/
int Step(Check start,PLStack &H) {
Element data;
int x=start.x-1,y=start.y-1;//将输入位置建议,数组从0,0开始存储
int i=1;
while(i<=64){
check[x][y]=i; //将当前步数写入棋盘数组
SetWeight(x,y);
struct Element t,data;
int pow_min=9;
for(int dir=1;dir<=8;dir++){ //探测下一步可走的方向
int x1=x+direction[0][dir];
int y1=y+direction[1][dir];
if(x1>=0&&x1<=7&&y1>=0&&y1<=7&&pow[x1][y1]!=9)
{
if(pow_min>pow[x1][y1]) //找出下一步位置中权值最小的
{
pow_min=pow[x1][y1];
t.d=dir; //上一步的方向
t.x=x1;
t.y=y1;
}
}
}
data.x=x; //入栈
data.y=y;
data.d=t.d;
Push(H,data);
x=t.x; //坐标更新
y=t.y;
i++; //步数增加
}
return OK;
}
int main(){
for(int i=0;i<M;i++) //棋盘初始化
for(int j=0;j<N;j++){
check[i][j]=0; //棋盘
next[i][j]=0; //轨迹棋盘
}
InitWeight(); //建立权值棋盘
PLStack H;
InitStack(H); //构造空栈H
Check start;
printf("请输入起始坐标x y:");
scanf("%d%d",&start.x,&start.y);
Step(start,H);
Printf(check);
return 0;
}