骑士巡游问题[回溯法]


问题:

  在 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