POJ 2488 A Knight's Journey

传送门:http://poj.org/problem?id=2488

 

    题目大意:在一个M X N的矩阵中,骑士需要从其中任意点出发,遍历所有点。

    骑士的走路规则:沿某一个方向A走两步,再沿这个方向的垂直方向B走一步。(A方向的两步不算,即一次到达最后点)

    图示:假设骑士在中间位置,则带有白色圆圈的8个点表示可以一次到达的位置。

    此题似乎只要找到一个能遍历的方法即可,但是题目的输出特别要求lexicographically,即按照字典顺序,竖直方向为1→M,水平方向为ABC……(共N个)。

    刚开始,这题我也没弄懂什么意思,在百度上看到很多大牛的解题报告,很多(±2,±1)的坐标我也没弄懂,现在回过头来看终于明白这些坐标及其放置顺序的意义:即依次按照我们已经给定的最优顺序来向下纵深的回溯,而这种最优顺序的最终结果是使输出按照最低的字典顺序。列图如下:

    如上图所示,在8个圆圈中,分别标记1-8,代表的即是坐标{(-2,-1),(-2,1),(-1,-2),(-1,2),(1,-2),(1,2),(2,-1),(2,1)} (x,y)表示横坐标移动x位,纵坐标移动y位。按照这个顺序搜寻可以得到最优解。

   了解了题意之后我们就可以比较轻松的分析出解法了:

    一、建立解空间,即上述表格,可以用一个二维数组visit[30][30],因为题目要求p*q<=26,因此p和q都是小于等于26的;

    二、要得到最优顺序,必须先从A1开始搜索,因此令visit[1][1] = 1;

    三、按照回溯法的步骤此时,backtrace(1,1,1)前两个1代表此时坐标为1,1,第三个代表此时才搜索了1个位置

    四、在backtrace()中,当搜索长度length = r * c时,代表已经遍历完所有结点,这时我们令flag = 1,便于在最后决定这个表格是否具有最优解。

    五、当length <= r * c时,则需要依次按照上述8个坐标的顺序搜索,并记下每次的x和y坐标。

 

算法如下:

#include <stdio.h>
int r , c ;//行、列
int visit[30][30];//visit[i][j] = 0表示未被访问,等于1表示被访问过
int xx[8] = {-2,-2,-1,-1,1,1,2,2};
int yy[8] = {-1,1,-2,2,-2,2,-1,1};
int px[30] , py[30];
int flag ;
int px[30],py[30];

int place(int x , int y)
{
    return x >= 1 && x <= c && y >=1 && y <= r ;
}

void backtrace(int x , int y , int length)
//分别表示当前搜索点的横纵坐标及搜索长度
{
    int m , n , i ;
    px[length] = x;
    py[length] = y;
    if(length == r * c)
    {
        flag = 1 ;
        return;
    }
    for(i = 0 ; i < 8 ; i ++)
    //依次按照8个优先顺序搜索
    {
        m = x + xx[i];
        n = y + yy[i];
        if(place(m,n)&&!visit[m][n]&&!flag)
        //m,n点未被访问,且可搜索
        {
            visit[m][n] = 1;
            backtrace(m,n,length+1);
            visit[m][n] = 0;//还原之,假设进入下一个结点
        }
    }
}

int main()
{
    int n , i = 1 , j;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%d%d",&r,&c);
        flag = 0 ;
        memset(visit,0,sizeof(visit));
        printf("Scenario #%d:\n",i++);
        visit[1][1] = 1;//首先访问A1
        backtrace(1,1,1);
        if(flag)
        {
            for(j = 1 ; j <= r * c ; j ++)
            {
                printf("%c",px[j]+'A'-1);
                printf("%d",py[j]);
            }
        }
        else
          printf("impossible");
        printf("\n\n");

    }

}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值