【騎士走棋盤】


/*
騎士走棋盤
說明:
騎士旅游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;
    }
    return 1;
}

 

運行結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM