马踏棋盘问题

来源:互联网 发布:社交网络 豆瓣 编辑:程序博客网 时间:2024/04/30 16:40

马踏棋盘问题

问题描述

马踏棋盘主要的解决方案有两种:一种是基于深度优先搜索的方法,另一种是基于贪婪算法的方法。第一种基于深度优先搜索的方法是比较常用的算法,深度优先搜索算法也是数据结构中的经典算法之一,主要是回溯的算法思想,可采用递归实现。贪婪的算法则是一步一步依据当前最优的策略,依靠每一步的局部最优,达到最终目标。但是他不一定能够得到最优解。

关于马踏棋盘的基本过程:国际象棋的棋盘为8*8的方格棋盘。现将”马”放在任意指定的方格中,按照”马”走棋的规则将”马”进行移动(如图所示,如果将空格标成点,就是象棋中的马走“日”字)。要求每个方格只能进入一次,最终使得”马”走遍棋盘的64个方格。如图所示,任意一个位置,“马”最多有8个方向可以跳动,所以每次都要依据这最多8个方向进行选择。

回溯法

这里写图片描述
深度优先搜索属于图算法的一种,英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次. (类似于树中的前序遍历,回溯法的思想)。

#include <stdio.h>#include <stdlib.h>#include <time.h>#define MATRIX 8#define TRUE 1#define ERROR 0typedef int status ;int tag = 1;/*查找下一步方向*/status nextStep(int (*chess)[MATRIX],int *x,int *y,int step){     switch(step)      {          case 0:              if(*y+2<=MATRIX-1 && *x-1>=0 && chess[*x-1][*y+2]==0)              {                  *y+=2;                  *x-=1;                  return TRUE;              }              break;          case 1:              if(*y+2<=MATRIX-1 && *x+1<=MATRIX-1 && chess[*x+1][*y+2]==0)              {                  *y+=2;                  *x+=1;                  return TRUE;              }              break;          case 2:              if(*y+1<=MATRIX-1 && *x+2<=MATRIX-1 && chess[*x+2][*y+1]==0)              {                  *y+=1;                  *x+=2;                  return TRUE;              }              break;          case 3:              if(*y-1>=0 && *x+2<=MATRIX-1 && chess[*x+2][*y-1]==0)              {                  *y-=1;                  *x+=2;                  return TRUE;              }              break;          case 4:              if(*y-2>=0 && *x+1<=MATRIX-1 && chess[*x+1][*y-2]==0)              {                  *y-=2;                  *x+=1;                  return TRUE;              }              break;          case 5:              if(*y-2>=0 && *x-1>=0 && chess[*x-1][*y-2]==0)              {                  *y-=2;                  *x-=1;                  return TRUE;              }              break;          case 6:              if(*y-1>=0 && *x-2>=0 && chess[*x-2][*y-1]==0)              {                  *y-=1;                  *x-=2;                  return TRUE;              }              break;          case 7:              if(*y+1<=MATRIX-1 && *x-2>=0 && chess[*x-2][*y+1]==0)              {                  *y+=1;                  *x-=2;                  return TRUE;              }              break;          default:              break;      }      return ERROR; }/*DFS棋盘*/void traverseChess(int (*chess)[MATRIX],int x,int y){    int count = 0;  //最多8个方向计数    int x1 = x,y1 = y;    if(x1<MATRIX && y1<MATRIX && chess[x1][y1] == 0){        chess[x1][y1] = tag;        tag ++;    }    if(tag > MATRIX * MATRIX){        printf("oK!!task has accomplished...\n");        return;    }    for(count = 0;count<8;count++){  //总共有8个可能的方向        nextStep(chess,&x1,&y1,count);        if(chess[x1][y1]==0)traverseChess(chess,x1,y1);  //递归    }}/*打印棋盘*/void print_chess(int (*chess)[MATRIX]){    int i = 0,j = 0;    printf("\nThe MATRIX is as follow\n");    for(i = 0;i<MATRIX;i++){        for(j = 0;j < MATRIX;j++){            printf("%2d\t",chess[i][j]);        }        printf("\n");    }}void main(){    int i ,j;    clock_t start ,end;    int chess[MATRIX][MATRIX];    for(i = 0; i<MATRIX;i++){        for(j = 0;j < MATRIX;j++){            chess[i][j] = 0;  //初始化        }    }    start = clock();    traverseChess(chess,4,0,1);  //开始遍历    end = clock();    print_chess(chess);  //打印棋盘    printf("共耗时:%f\n",(double)(end-start)/CLOCKS_PER_SEC); }

贪心算法

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
在处理马踏棋盘问题时,每次在至多8个可选的方向中,首先通过验证其中一个方向可以成功。贪心算法同样是试探至多的八个可能的出口,但是八个出口的排序并非按照前述的顺时针,而是按照每个可能出口的进一步出口数的递增排序,所以每次先试探的总是进一步出口较少的出口,能够给之后的出口更多的选择,因此贪心算法是比较高效的,而且它不回溯。

#include <stdio.h>#include <stdlib.h>#include <math.h>#include <time.h>#define ROWS    8#define COLS    8/*cursor i move chess*/const int iktmove[8] = {-2,-1,1,2,2,1,-1,-2};/*cursor j move chess*/const int jktmove[8] = {1,2,2,1,-1,-2,-2,-1};int chess[ROWS][COLS];/*inital the chess*/void chess_init(int chess[][COLS],int rows,int cols){    int i, j;    for(i = 0; i < rows ; ++ i)        for (j = 0; j < cols ; ++ j)        {            chess[i][j] = 0;        }} /*print the chess*/void print_chess(int chess[][COLS]){    int i,j;    for(i = 0; i < ROWS; ++ i)    {        for(j = 0; j < COLS; ++ j)            printf("%d\t",chess[i][j]);        printf("\n\n");    }}/*find the index of min non-zeros*/int minindex(int a[],int cols){    int i = 0,index = 0;    int min = a[0];    for(i = 0 ; i< cols; ++ i)    {        if(a[i] >0)        {            min = a[i];            index = i;            break;        }    }    for(i = index + 1; i < cols ; ++ i)    {        if(a[i] > 0 && min > a[i])        {            min = a[i];            index = i;        }    }    if(a[index] > 0)        return index;    return -1;}/**/void greedy_chess(int chess[][COLS],int rows,int cols,int start_i,int start_j){    int i,npos,m,min,j,nnpos;    int nexti[8] = {0,0,0,0,0,0,0,0};    int nextj[8] = {0,0,0,0,0,0,0,0};    int exit[8] = {0,0,0,0,0,0,0,0};    /*init*/    chess_init(chess,rows,cols);    /*first step*/    chess[start_i][start_j] = 1;    /*n>1 step*/    for(m = 1; m < 64; ++ m)    {        /*steps d*/        npos = 0;        for(i = 0; i < 8; ++ i)        {            /*ignore the point which doesn't satisfy the conditions*/            if( start_i + iktmove[i] < 0 ||                start_i + iktmove[i] >= rows ||                start_j + jktmove[i] < 0 ||                start_j + jktmove[i] >= cols ||                chess[start_i + iktmove[i]][start_j+jktmove[i]] > 0)            {                continue;            }            /*save the point which satisfy the conditions*/            nexti[npos] = start_i + iktmove[i];            nextj[npos] = start_j + jktmove[i];            /*statistics how many point satisfy conditions*/            npos ++;        }        /*steps e*/        if(npos == 0)        {            printf("Can not finish the game!!\n,The steps of game can be %d\n",m);                return;        }        /*steps e*/        if(npos == 1)        {            min = 0;            start_i = nexti[min];            start_j = nextj[min];            chess[start_i][start_j] = m+1;        }        /*steps f*/        if(npos > 1)        {            for(i = 0; i < npos ; ++ i)            {                nnpos = 0;                for(j = 0; j < 8; ++ j)                {                    if( nexti[i] + iktmove[j] >= 0 &&                         nexti[i] + iktmove[j] < rows &&                        nextj[i] + jktmove[j] >= 0 &&                        nextj[i] + jktmove[j] < cols &&                        chess[nexti[i] + iktmove[j]][nextj[i] + jktmove[j]] == 0)                    {                        nnpos ++;                    }                }                exit[i] = nnpos;            }            if((min = minindex(exit,npos)) >= 0)            {                start_i = nexti[min];                start_j = nextj[min];                chess[start_i][start_j] = m+1;            }            else            {                printf("Can not finish the game!!\n,The steps of game can be %d\n",m);                return;            }        }    }}void main(){    clock_t start,end;    start = clock();    greedy_chess(chess,ROWS,COLS,5,1);    end = clock();    print_chess(chess);    printf("time consumed:%f\n",(double)(end-start)/CLOCKS_PER_SEC); }
0 0