騎士巡游問題[回溯法]


問題:

  在 n × n 方格的國際象棋棋盤上,馬(也稱為騎士Knight)從任意指定的方格出發,以跳馬規則(橫一步豎兩步或橫兩步豎一步),周游棋盤的每一個格子,要求每個格子只能跳過一次。 

思路:

  搜索部分就是普通的回溯   

void KnightPatrol(int n, int count, step steps[], int map[][8])
{//n表示棋盤規模,count表示騎士已經走過的步數,steps記錄騎士巡游過的點,map用來標記地圖上每個點有沒被走過

    if (count == n*n)
    {//如果騎士巡游過了所有的點
        display(steps, n);
    }

    for (int i = N; i <= NW; i++)
    {//對每個方向遍歷

        step then = overlook(steps[count], i);//向i方向眺望一下
        bool lonely = false;
        if (count % 2 == 0)
        {
            lonely = hasLonelyPoint(map, n);
        }
        if (isInside(n, then) && !isOverlap(map, then) && !lonely)
        {//如果騎士下一步沒有跑到地圖外面,且沒有走到剛才走過的地方
            //並且地圖中沒有走不到的點

            patrol(steps, count, then, map);            
            KnightPatrol(n, count + 1, steps, map);
            map[steps[count + 1].x][steps[count + 1].y] = 0;
        }
    }
}

 

但是我這里設計了一個剪枝函數,具體思路就是每走一步,就判斷下地圖中是否有永遠不能被走到的點

就是因為這個棒棒噠剪枝函數,運行速度提高了不知道多少 

bool hasLonelyPoint(int map[][8], int n)
{//判斷地圖中是否有孤立的點,即怎么都走不到的點
    step point1, point2;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1, count = 0; j <= n; j++)
        {
            if (map[i][j] == 0)
            {
                point1.x = i;
                point1.y = j;
                int count = 0;
                for (int k = N; k <= NW; k++)
                {
                    point2 = overlook(point1, k);
                    if (!isInside(n, point2)) count++;//point1 周圍的8個點中有點在地圖外
                    if (map[point2.x][point2.y] == 1) count++;//point1 周圍的8個點中有點被踩過
                }
                if (count >= 8) return true;//如果8個方向全都不行,說明這個點永遠都無法被走到了
            }
        }
    }
    return false;
}

 


免責聲明!

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



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