马踏棋盘问题

马踏棋盘问题

问题描述

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

关于马踏棋盘的基本过程:国际象棋的棋盘为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 0
typedef 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); 

}
1.算法是程序的灵魂,优秀的程序在对海量数据处理时,依然保持高速计算,就需要高效的数据结构和算法支撑。2.网上数据结构和算法的课程不少,但存在两个问题:1)授课方式单一,大多是照着代码念一遍,数据结构和算法本身就比较难理解,对基础好的学员来说,还好一点,对基础不好的学生来说,基本上就是听天书了2)说是讲数据结构和算法,但大多是挂羊头卖狗肉,算法讲的很少。 本课程针对上述问题,有针对性的进行了升级 3)授课方式采用图解+算法游戏的方式,让课程生动有趣好理解 4)系统全面的讲解了数据结构和算法, 除常用数据结构和算法外,还包括程序员常用10大算法:二分查找算法(非递归)、分治算法、动态规划算法、KMP算法、贪心算法、普里姆算法、克鲁斯卡尔算法、迪杰斯特拉算法、弗洛伊德算法、棋盘算法。可以解决面试遇到的最短路径、最小生成树、最小连通图、动态规划等问题及衍生出的面试题,让你秒杀其他面试小伙伴3.如果你不想永远都是代码工人,就需要花时间来研究下数据结构和算法。教程内容:本教程是使用Java来讲解数据结构和算法,考虑到数据结构和算法较难,授课采用图解加算法游戏的方式。内容包括: 稀疏数组、单向队列、环形队列、单向链表、双向链表、环形链表、约瑟夫问题、栈、前缀、中缀、后缀表达式、中缀表达式转换为后缀表达式、递归与回溯、迷宫问题、八皇后问题、算法的时间复杂度、冒泡排序、选择排序、插入排序、快速排序、归并排序、希尔排序、基数排序(桶排序)、堆排序、排序速度分析、二分查找、插值查找、斐波那契查找、散列、哈希表、二叉树、二叉树与数组转换、二叉排序树(BST)、AVL树、线索二叉树、赫夫曼树、赫夫曼编码、多路查找树(B树B+树和B*树)、图、图的DFS算法和BFS、程序员常用10大算法、二分查找算法(非递归)、分治算法、动态规划算法、KMP算法、贪心算法、普里姆算法、克鲁斯卡尔算法、迪杰斯特拉算法、弗洛伊德算法棋盘算法。学习目标:通过学习,学员能掌握主流数据结构和算法的实现机制,开阔编程思路,提高优化程序的能力。
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页