蓝桥杯2016年第七届真题-路径之谜

题目:

小明冒充X星球的骑士,进入了一个奇怪的城堡。

城堡里边什么都没有,只有方形石头铺成的地面。

假设城堡地面是 n x n 个方格。如上图所示。

按习俗,骑士要从西北角走到东南角。

可以横向或纵向移动,但不能斜着走,也不能跳跃。

每走到一个新方格,就要向正北方和正西方各射一箭。

(城堡的西墙和北墙内各有 n 个靶子)

同一个方格只允许经过一次。但不必走完所有的方格。

如果只给出靶子上箭的数目,你能推断出骑士的行走路线吗?

有时是可以的,比如上图中的例子。

本题的要求就是已知箭靶数字,求骑士的行走路径(测试数据保证路径唯一)


输入:

第一行一个整数N(0<N<20),表示地面有 N x N 个方格

第二行N个整数,空格分开,表示北边的箭靶上的数字(自西向东)

第三行N个整数,空格分开,表示西边的箭靶上的数字(自北向南)

输出:

一行若干个整数,表示骑士路径。

为了方便表示,我们约定每个小格子用一个数字代表,从西北角开始编号: 0,1,2,3....

比如,上图中的方块编号为:

0 1 2 3

4 5 6 7

8 9 10 11

12 13 14 15


eg:


代码写的注释挺详细的,直接看代码吧,代码如下:

#include<iostream>
using namespace std;

int n;    // n * n 个方格 ,0<n<20
int a[20],b[20];  //a为自西向东的靶数,b为自北向南的靶数
int arr[20][20];   //构建二维数组,代表格子
int vis[20][20] = {0};   // 标记此点是否被走过,每个点只能走一次

int top;  //栈顶
int stack[20];  //调用栈,储存路径(最终经过的路程,即答案)
int dx[4] = {1,0,-1,0};  //以中间为中心点,代表方向坐标,对应下左上右
int dy[4] = {0,-1,0,1};   //下左上右,如图

//检查靶子上的靶数 是否为0,为0路径正确,否则路径不正确
bool check() {
    for(int i=0; i<n; i++) {
        if(a[i] != 0 || b[i] != 0) {
            return false;
        }
        return true;
    }
}

void dfs(int x,int y,int step) {
    //如果要射的箭数<0,说明多射了一箭,再走下去是不对的
    if(a[y]<0||b[x]<0)
        return;
    //终止条件 ,到达最后一个格子,坐标为(n-1,n-1)
    if(x==n-1&&y==n-1) {
        //靶数对应正确则输出,否则继续递归
        if(check()) {
            for(int i=0; i<top; i++)
                cout<<stack[i]<<"";
            cout<<endl;
        }
        return ;
    }
    //判断下一步方向,共四个方向
    for(int i=0; i<4; i++) {
        int tx,ty;  //下一点的坐标
        tx=x+dx[i];
        ty=y+dy[i];
        //未被访问且超出格子
        if(vis[tx][ty]==0&&tx>=0&&tx<n&&ty>=0&&ty<n) {
            vis[tx][ty] = 1;  //标记为访问
            stack[top++] = arr[tx][ty];  //格子对应标记入栈
            a[ty]--;  //靶数对应减1
            b[tx]--;
            dfs(tx, ty, step+1);   //从当前坐标继续向后走(递归调用)
            a[ty]++;   //回溯(靶数对应加1)
            b[tx]++;
            top--;  //出栈
            vis[tx][ty] = 0;  //标记为未访问
        }
    }
}

int main() {
    cin >> n; 
    
    //输入靶数
    for (int i = 0; i < n; i++)
        cin >> a[i];
        
    for (int i = 0; i < n; i++)
        cin >> b[i];
        
    //初始化格子标记0,1,2,3,4,...,n-1
    for (int i = 0,k=0; i < n; i++)
        for (int j = 0; j < n; j++)
            arr[i][j] = k++;
            
    //从第一个格子开始,将第一个格子做一些初始化
    vis[0][0] = 1;   //标记为访问
    stack[0] = arr[0][0];   //入栈
    top = 1;   //栈内元素个数为1
    a[0]--;      //对应靶数减1
    b[0]--;
    dfs(0, 0, 1);     //从坐标(0,0)开始向后走
    return 0;
}

代码注释中提到的图如下图所示:

右下角还有一个方块,整个是个长方体的形状,大家自行脑补

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

糊涂苏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值