一點一滴算法 騎士走棋盤

/*
騎士走棋盤
說明:
騎士旅遊Knight tour在十八世紀初倍受數學家與拼圖迷的注意,它什麼時候被提出已不可考,騎士的走法爲西洋
棋的走法,騎士可以由任一個位置出發,它要如何走完所有的位置。

解法:
騎士的走法,基本上可以用遞回來解決,但是純粹的遞迴在維度大時相當沒有效率,一個聰明的解法由J.CWarnsdorff
在1823年提出, 簡單地說,先將最難的位置走完,接下來的路就寬廣了,騎士所想要的下一步,爲下一不再 選
擇時,所能走的步數最少的一步。使用這個方法,在不使用遞迴的情況下,可以有較高的機率找出走法(找不到走
的機率也是有的) 
*/ 

 

#include <stdio.h>

int pos[8][8] = {0};

int travel(int, int);

int main()
{
    int i, j, startX, startY;
    while(1)
    {
        printf("輸入起始點:");
        scanf("%d%d", &startX, &startY);
        if(travel(startX, startY)) {
            printf("遊歷完成!\n");
        }else {
            printf("遊歷失敗!\n");
        }
        for(i=0; i<8; i++) {
            for(j=0; j<8; j++) {
                printf("%2d ", pos[i][j]);
            }
            printf("\n");
        }
        printf("\n");
    }
    
    return 0;
}

int travel(int x, int y) {
    int i, j, k, l, m;
    int tmpX, tmpY;
    int count, min, tmp;

    //騎士可走的八個方向(順時針)
    int ktmoveX[8] = {1, 2, 2, 1, -1, -2, -2, -1};
    int ktmoveY[8] = {-2, -1, 1, 2, 2, 1, -1, -2};

    //測試下一步座標
    int nextX[8] = {0};
    int nextY[8] = {0};

    //記錄每個方向的出路的個數
    int exists[8] = {0};

    //起始用1標記位置
    i = x;
    j = y;
    pos[i][j] = 1;

    //遍歷棋盤
    for(m=2; m<=64; m++) {
        //初始化八個方向出口個數
        for(l=0; l<8; l++) {
            exists[l] = 0;
        }
        l = 0; //計算可走方向

        //試探八個方向
        for(k=0; k<8; k++) {
            tmpX = i + ktmoveX[k];
            tmpY = j + ktmoveY[k];
            //邊界 跳過
            if(tmpX<0 || tmpY<0 || tmpX>7 || tmpY>7) {
                continue;
            }
            //可走 記錄
            if(pos[tmpX][tmpY] == 0) {
                nextX[l] = tmpX;
                nextY[l] = tmpY;
                l++;    //可走方向加1
            }
        }
        count = l;
        //無路可走 返回
        if(count == 0) {
            return 0;
        //一個方向可走 標記
        }else if(count == 1) {
            min = 0;
        //找出下個位置出路個數
        }else {
            for(l=0; l<count; l++) {
                for(k=0; k<8; k++) {
                    tmpX = nextX[l] + ktmoveX[k];
                    tmpY = nextY[l] + ktmoveY[k];
                    if(tmpX<0 || tmpY<0 || tmpX>7 || tmpY>7) {
                        continue;
                    }
                    if(pos[tmpX][tmpY] == 0) {
                        exists[l]++;
                    }
                }
            }
            //找出下個位置出路最少的方向  找最難的路 纔會擴展接下來的路
            min = 0;
            tmp = exists[0];
            for(l=0; l<count; l++) {
                if(exists[l] < tmp) {
                    tmp = exists[l];
                    min = l;
                }
            }
        }
        //用序號標記走過的位置
        i = nextX[min];
        j = nextY[min];
        pos[i][j] = m;//position[i][j]就是 下一步要走的地方
    }
    return 1;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章