马踏棋盘的实现

发布者:MysticalGarden最新更新时间:2015-05-05 来源: 51hei关键字:马踏棋盘  程序设计  数据结构 手机看文章 扫描二维码
随时随地手机看文章
马踏棋盘是经典的程序设计问题之一,主要的解决方案有两种:一种是基于深度优先搜索的方法,另一种是基于贪婪算法的方法。第一种基于深度优先搜索的方法是比较常用的算法,深度优先搜索算法也是数据结构中的经典算法之一,主要是采用递归的思想,一级一级的寻找,最后找到合适的解。而基于贪婪的算法则是依据贪婪算法的思想设置一种标准,然后依据标准进行选择,从而得到解,但是他不一定能够得到最优解。

 
关于马踏棋盘的基本过程:国际象棋的棋盘为8*8的方格棋盘。现将"马"放在任意指定的方格中,按照"马"走棋的规则将"马"进行移动。要求每个方格只能进入一次,最终使得"马"走遍棋盘的64个方格。
 
深度优先搜索属于图算法的一种,英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次. (来自百度)

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题他能产生整体最优解或者是整体最优解的近似解。(来自百度)

其中基于深度优先搜索的算法就是依据当前点找到下一个可能的点,然后对这个点进行深度优先搜索,然后依次递归,当出现条件不满足时,退回来,采用其他的路劲进行搜索,最后肯定能够得到对应的结果。实现的基本过程如下:

    /*deepsearch to solve the horse chess problem*/
    #include
    #include
    #include
    #define ROWS    8
    #define COLS    8

    int chess[ROWS][COLS];

    /*eight directions of x moved*/
    const int x_move[] = {-2,-1,1,2,2,1,-1,-2};
    /*eight directions of y moved*/
    const int y_move[] = {1,2,2,1,-1,-2,-2,-1};

    void print_matrix()
    {
        int i = 0,j = 0;
        for (i = 0; i < ROWS; ++ i)
        {
            for (j = 0; j < COLS; ++ j)
            {
                printf("%d ",chess[i][j]);
            }
            printf(" ");
        }
    }

    /*find the next point*/
    int nextxy(int *x,int *y,int count)
    {
        if(count > 7 && count < 0)
            return -1;
        switch(count)
        {
        case 0:
            /*check the conditions*/
            if(*x + x_move[0] < ROWS &&
             *x + x_move[0]>= 0 &&
             *y + y_move[0]< COLS &&
             *y + y_move[0]>= 0 &&
             chess[*x + x_move[0]][*y + y_move[0]] == 0)
            {
                *x += x_move[0];
                *y += y_move[0];
                break;
            }
            else/*failed*/
                return 0;
        case 1:
            if(*x + x_move[1] < ROWS &&
                *x + x_move[1]>= 0 &&
                *y + y_move[1]< COLS &&
                *y + y_move[1]>= 0 &&
             chess[*x + x_move[1]][*y + y_move[1]] == 0)
            {
                *x += x_move[1];
                *y += y_move[1];
                break;
            }
            else
                return 0;
        case 2:
            if(*x + x_move[2] < ROWS &&
                *x + x_move[2]>= 0 &&
                *y + y_move[2]< COLS &&
                *y + y_move[2]>= 0 &&
             chess[*x + x_move[2]][*y + y_move[2]] == 0)
            {
                *x += x_move[2];
                *y += y_move[2];
                break;
            }
            else
                return 0;
        case 3:
            if(*x + x_move[3] < ROWS &&
                *x + x_move[3]>= 0 &&
                *y + y_move[3]< COLS &&
                *y + y_move[3]>= 0 &&
             chess[*x + x_move[3]][*y + y_move[3]] == 0)
            {
                *x += x_move[3];
                *y += y_move[3];
                break;
            }
            else
                return 0;
        case 4:
            if(*x + x_move[4] < ROWS &&
                *x + x_move[4]>= 0 &&
                *y + y_move[4]< COLS &&
                *y + y_move[4]>= 0 &&
             chess[*x + x_move[4]][*y + y_move[4]] == 0)
            {
                *x += x_move[4];
                *y += y_move[4];
                break;
            }
            else
                return 0;
        case 5:
            if(*x + x_move[5] < ROWS &&
                *x + x_move[5]>= 0 &&
                *y + y_move[5]< COLS &&
                *y + y_move[5]>= 0 &&
             chess[*x + x_move[5]][*y + y_move[5]] == 0)
            {
                *x += x_move[5];
                *y += y_move[5];
                break;
            }
            else
                return 0;
        case 6:
            if(*x + x_move[6] < ROWS &&
                *x + x_move[6]>= 0 &&
                *y + y_move[6]< COLS &&
                *y + y_move[6]>= 0 &&
                chess[*x + x_move[6]][*y + y_move[6]] == 0)
            {
                *x += x_move[6];
                *y += y_move[6];
                break;
            }
            else
                return 0;
        case 7:
            if(*x + x_move[7] < ROWS &&
                *x + x_move[7]>= 0 &&
                *y + y_move[7]< COLS &&
                *y + y_move[7]>= 0 &&
             chess[*x + x_move[7]][*y + y_move[7]] == 0)
            {
                *x += x_move[7];
                *y += y_move[7];
                break;
            }
            else
                return 0;
        default:
            return 0;
        }
        return 1;
    }
    int deepsearch(int x,int y, int j)
    {
        /*save the value x,y*/
        int x1 = x, y1 = y;
        int tag = 0, i = 0;
        /*save j on chess[x][y]*/
        chess[x][y] = j;

        /*recursion exit condition*/
        if(j == COLS*ROWS)
        {
            return 1;
        }
        /*find the next point in eight directions*/
        tag = nextxy(&x1,&y1,i);
        /*find the nextx,nexty */
        while (tag == 0 && i < 7)
        {
            i ++;
            tag = nextxy(&x1,&y1, i);
        }

        /*the nextxy be found*/
        while(tag)
        {
            if(deepsearch(x1,y1,j+1))
                return 1;

         /*if failed, a new finding process */
            x1 = x; y1 = y;
            i ++;
            tag = nextxy(&x1,&y1,i);
            while (tag == 0 && i < 7)
            {
                i ++;
                tag = nextxy(&x1,&y1,i);
            }
        }
        /*no direction can find next point*/
        if(tag == 0)
            chess[x][y] = 0;
        return 0;
    }

    void main()
    {
        clock_t start = clock();
        deepsearch(2,0,1);
        print_matrix();
        int seconds = (clock()-start)/CLOCKS_PER_SEC;

        printf(" %d ",seconds);
        return;
    }[page]

采用贪婪算法的实现,首先应该设置一定的判断准则,然后根据设定的准则进行选择,在马踏棋盘中设定的准备是选择出路最少(至少为1)的一个方向为准则,能够实现马踏棋盘问题的解决。当然该问题为什么要选择出路最少,我暂时还不是很清楚。基本的实现如下:

 

    #include
    #include
    #include

    #define ROWS    8
    #define COLS    8

    /*axis i move matrix*/
    const int iktmove[8] = {-2,-1,1,2,2,1,-1,-2};
    /*axis j move matrix*/
    const int jktmove[8] = {1,2,2,1,-1,-2,-2,-1};

    int board[ROWS][COLS];

    /*inital the matrix*/
    void matrix_init(int matrix[][COLS],int rows,int cols)
    {
        int i, j;
        for(i = 0; i < rows ; ++ i)
            for (j = 0; j < cols ; ++ j)
            {
                matrix[i][j] = 0;
            }
    }
    /*print the matrix*/
    void print_matrix(int matrix[][COLS],int rows,int cols)
    {
        int i,j;
        for(i = 0; i < rows; ++ i)
        {
            for(j = 0; j < cols; ++ j)
                printf("%d ",matrix[i][j]);
            printf(" ");
        }
    }
    /*find the index of min non-zeros positive*/
    int minindex_in_matrix(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;
    }
    int maxindex_in_matrix(int a[],int cols)
    {
        int i = 0,index;
        int max ;
        for(i = 0 ; i< cols; ++ i)
        {
            if(a[i] >0)
            {
                max = a[i];
                index = i;
                break;
            }
        }
        for(i = index + 1; i < cols ; ++ i)
        {
            if(a[i] > 0 && max < a[i])
            {
                max = a[i];
                index = i;
            }
        }
        if(a[index] > 0)
            return index;
        return -1;
    }

    /**/
    void warnsdorff_role(int matrix[][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};
        
        /*steps a*/
        matrix_init(matrix,rows,cols);
        /*steps b*/
        matrix[start_i][start_j] = 1;
        /*steps c*/
        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 ||
                    matrix[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!! ,The steps of game can be %d ",m);    
                goto print;
            }
            /*steps e*/
            if(npos == 1)
            {
                min = 0;
                goto set_nextpoint;
            }
            /*steps f*/
            if(npos > 1)
            {
                /*calculate the possible way of the next next step */
                for(i = 0; i < npos ; ++ i)
                {
                    nnpos = 0;
                    for(j = 0; j < 8; ++ j)
                    {
                        /*statistics the point which satisfy conditions*/
                        if( nexti[i] + iktmove[j] >= 0 &&
                            nexti[i] + iktmove[j] < rows &&
                            nextj[i] + jktmove[j] >= 0 &&
                            nextj[i] + jktmove[j] < cols &&
                            matrix[nexti[i] + iktmove[j]][nextj[i] + jktmove[j]] == 0)
                        {
                            nnpos ++;
                        }
                    }
                    /*save the numbers of points for next step*/
                    exit[i] = nnpos;
                }
                /*find the proper point*/
                if((min = minindex_in_matrix(exit,npos)) >= 0)
                {
                    goto set_nextpoint;
                }
                else /*failed*/
                {
                    printf("Can not finish the game!! ,The steps of game can be %d ",m);
                    goto print;
                }
            }
    set_nextpoint:
            /*step g*/
            /*set the next start point of game*/
            start_i = nexti[min];
            start_j = nextj[min];
            matrix[start_i][start_j] = m+1;
        }
    print:
        /*step h*/
        print_matrix(matrix,rows,cols);
    }

    void main()
    {
        warnsdorff_role(board,ROWS,COLS,5,1);
    }

实现结果:当采用深度优先搜索算法的过程中发现当棋盘为8X8时,计算速度非常的慢,而当棋盘为5X5以后,计算速度非常的快速。说明算法存在一定的缺陷。而采用贪婪算法实现的速度非常的快,棋盘的大小对算法性能影响较小。

将矩阵改为5X5得到如下的结果:从结果中可以看见两种算法得到的结果存在一定的差异,但是都能解决马踏棋盘问题。

1、深度优先搜索算法:

2、贪婪算法:

关键字:马踏棋盘  程序设计  数据结构 引用地址:马踏棋盘的实现

上一篇:同步与异步IO、阻塞与非阻塞IO
下一篇:void *指针的妙用

推荐阅读最新更新时间:2024-03-16 14:00

STM32 IAP程序设计以及问题
一、IAP实现方法: 1、编译firmware时,从axf文件转换成bin文件并对bin文件进行加密处理; 2、通过PC机软件 固件升级 功能把加密后的bin文件下载到SPI Flash中; 3、ARM接收完毕新的固件并校验后设置固件升级信息,然后复位系统; 4、在ARM系统中,前4KB包含IAP(在线编程)程序。IAP在启动时首先检查固件升级信息区,如果有升级内容则根据信息区内容从SPI Flash中读取并解密固件,然后写入ARM的内部Flash。 5、升级完毕后,IAP调用固件程序执行正常程序功能; 二、IAP程序的要求和基本流程: 1、IAP程序不需要从串口、USB口或以太网接收数据,固件传输由应用软件自行完成; 2、IAP
[单片机]
22课:单片机串行口通信程序设计
1.串行口方式0应用编程 8051单片机串行口方式0为移位寄存器方式,外接一个串入并出的移位寄存器,就能扩展一个并行口。 单片机串行口通信程序设计硬件连接图 例:用8051单片机串行口外接CD4094扩展8位并行输出口,如图所示,8位并行口的各位都接一个发光二极管,要求发光管呈流水灯状态。 串行口方式0的数据传送可采用中断方式,也可采用查询方式,无论哪种方式,都要借助于TI或RI标志。串行发送时,能靠TI置位(发完一帧数据后)引起中断申请,在中断服务程序中发送下一帧数据,或者通过查询TI的状态,只要TI为0就继续查询,TI为1就结束查询,发送下一帧数据。在串行接收时,则由RI引起中断或对RI查询来确定何时接收下一帧数据。
[单片机]
22课:单片机串行口通信<font color='red'>程序设计</font>
PIC单片机人机接口模块4×4行列式键盘的程序设计
程序的主流程如图1所示。   图1 程序的主流程   程序主要分为两个部分:一个部分不停地监测是否有按键按下,另一个部分查看哪一个键按下。   在初始状态下,4个列输出端口输出低电平,即RD0~RD3输出低电平,然后持续监测4个行输入端口RD4~RD7的状态是不是高电平。   如果没有按键按下,则RD4~RD7的状态是高电平;如果有按键按下,则被按下的键对应的行输入端口的电平就会被拉低,RD4~RD7会有低电平出现,对4个行输入端口RD4~RD7的电平的监测即为对按键的监测。   在4个行输入端口RD4~RD7上出现低电平时,就转到查询程序SEE。键盘扫描子程序流程如图2所示,按键查询子程序流程如图3所示。
[单片机]
PIC单片机人机接口模块4×4行列式键盘的<font color='red'>程序设计</font>
pic18f4550 USB 程序设计
发现pic usb内部设计原理跟飞思卡尔单片机usb硬件结构差不多!都需要通过缓冲描述表(DBT)来获端点信息。 第一步:初始化usb设备( 配置全速 使能内部上拉电阻 等) void InitializeUSBDriver(void) 第二步: 等待usb中断。接收中断跳转到相应的服务代码 void USBDriverService(void) { if(usb_device_state == DETACHED_STATE) return; if(ACTVIF && ACTVIE) USBWakeFromSuspend(); //唤醒中断 if(SUSPND==1) return; if(URSTI
[单片机]
pic18f4550 USB <font color='red'>程序设计</font>
PIC单片机的查表程序设计
PIC的查表程序可以利用子程序带值返回的特点来实现。具体是在主程序中先取表数据地址放入W,接着调用子程序,子程序的第一条指令将W置入PC,则程序跳到数据地址的地方,再由“RETLW”指令将数据放入W返回到主程序。下面程序以F10放表头地址。 MOVLW  TABLE     ;表头地址→F10 MOVWF  10 ┋ MOVLW  1        ;1→W,准备取“1”的线段值 ADDWF  10,1      ;F10+W =“1”的数据地址 CALL  CONVERT MOVWF  6        ;线段值置到B口,点亮LED ┋ CONVERT MOVWF  2        ;W→PC TABLE RETLW  0
[单片机]
PIC单片机的查表<font color='red'>程序设计</font>
51单片机定时器与中断的程序设计
P2.0~P2.2 分别接上了独立按键 K0、K1、K2。 P1 接上了 8 个 LED,输出低电平时发光。 要求: 按下 K1 键,P1.7 输出周期为 1s 的方波; 按下 K2 键,P1 输出循环流水灯,每 2 个灯亮 0.5s; 按下 K0 键,停止方波和流水灯的输出。 ;----------------------------------------- ; ORG 0000H JMP START ORG 000BH ; JMP T0_INT T0_INT: MOV TH0, #(65536 - 50000) / 256 MOV TL0, #(65536 - 50000) MOD 256 DJNZ
[单片机]
51单片机定时器与中断的<font color='red'>程序设计</font>
单片机C语言程序设计:LED 模拟交通灯
/* 名称:LED 模拟交通灯 说明:东西向绿灯亮若干秒,黄 灯闪烁 5 次后红灯亮, 红灯亮后,南 北向由红灯变为绿灯,若干秒后南北 向黄灯闪烁 5 此后变红灯,东西向变 绿灯,如此重复。 */ #include reg51.h #define uchar unsigned char #define uint unsigned int sbit RED_A=P0^0; //东西向灯 sbit YELLOW_A=P0^1; sbit GREEN_A=P0^2; sbit RED_B=P0^3; //南北向灯 sbit YELLOW_B=P0^4; sbit GREEN_B=P0^5; uchar
[单片机]
单片机C语言<font color='red'>程序设计</font>:LED 模拟交通灯
基于PCI总线的实时测频卡WDM驱动程序设计
  PCI总线是一种与CPU无关的32/64位地址数据复用总线,工作频率为33 MHz/66 MHz,它支持突发传输,具有即插即用、电源管理等功能。PCI总线以其优良性能和可适应性成为现代微机的主流总线。在开发PCI设备的过程中,需要为PCI设备写驱动程序。Windows驱动程序模型(WDM)是Microsoft公司力推的全新驱动程序模式,它支持PhP、电源管理和WMI等技术。在Windows操作平台上,WDM已成为主流的驱动模型。这里主要介绍根据工程背景开发的基于PCI总线的实时测频卡的WDM驱动程序设计。   1实时测频卡硬件系统结构   实时测频卡的主要功能是实时测定信号频率,实时识别信号调制方式。系统的电路框图如图1所示
[嵌入式]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

更多每日新闻
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved