面试题13:机器人的运动范围(回溯法)

题目:地上有m行n列的方格。一个机器人从坐标(0,0)的格子开始移动,它每次可以向左、右、上、下移动一格,但不能进入行坐标和列坐标的数位之和大于k的格子。

例如:当k为18时,机器人能够进入方格(35,37),因为3+5+3+7=18.但它不能进入方格(35,38),因为3+5+3+8=19.请问机器人能够到达多少个格子?

一、算法实现 

该方格看作一个 m x n 的矩阵,在这个矩阵中,除边界上的格子之外,其他格子都有4个相邻的格子。

机器人从坐标(0,0)开始移动。当它准备进入坐标为(i,j)的格子时,通过检查坐标的数位和来判断机器人是否能够进入。如果机器人能够进入坐标为(i,j)的格子,则再判断它能否进入4个相邻的格子(i,j-1)、(i-1,j)、(i,j+1)、(i+1,j)。

因此,我们用如下的代码来实现回溯算法。

int movingCount(int threshold, int rows, int cols)//限定大小k,矩阵行数,列数
{
    if (threshold < 0 || rows <= 0 || cols <= 0)//判断所给前提条件是否可行
        return 0;

    bool* visited = new bool[rows * cols];//监视矩阵,确保每个格子不会重复进入
    for (int i = 0; i < rows * cols; ++i)
        visited[i] = false;

    int count = movingCountCore(threshold, rows, cols,
        0, 0, visited);

    delete[] visited;//释放空间

    return count;
}
int movingCountCore(int threshold, int rows, int cols, int row,
    int col, bool* visited)//统计总共能进入格子的个数
{
    int count = 0;
    if (check(threshold, rows, cols, row, col, visited))//判断该格子是否满足条件
    {
        visited[row * cols + col] = true;//标记该格子,避免再次进入

        count = 1 + movingCountCore(threshold, rows, cols,
            row - 1, col, visited)
            + movingCountCore(threshold, rows, cols,
                row, col - 1, visited)
            + movingCountCore(threshold, rows, cols,
                row + 1, col, visited)
            + movingCountCore(threshold, rows, cols,
                row, col + 1, visited);
    }

    return count;
}

下面的函数check用来判断机器人能否进入坐标为(row,col)的方格,而函数getDigitSum用来得到一个数字的数位之和。

bool check(int threshold, int rows, int cols, int row, int col,
    bool* visited)//判断当前格子是否满足行,列的数字按位相加不大于限定数字k,并且该格子是第一次进入
{
    if (row >= 0 && row < rows && col >= 0 && col < cols
        && getDigitSum(row) + getDigitSum(col) <= threshold
        && !visited[row * cols + col])
        return true;

    return false;
}
int getDigitSum(int number)//实现数字按位相加
{
    int sum = 0;
    while (number > 0)
    {
        sum += number % 10;
        number /= 10;
    }

    return sum;
}

二、测试代码 

// ====================测试代码====================
void test(char* testName, int threshold, int rows, int cols, int expected)
{
    if (testName != nullptr)
        printf("%s begins: ", testName);

    if (movingCount(threshold, rows, cols) == expected)
        printf("Passed.\n");
    else
        printf("FAILED.\n");
}

// 方格多行多列
void test1()
{
    test("Test1", 5, 10, 10, 21);
}

// 方格多行多列
void test2()
{
    test("Test2", 15, 20, 20, 359);
}

// 方格只有一行,机器人只能到达部分方格
void test3()
{
    test("Test3", 10, 1, 100, 29);
}

// 方格只有一行,机器人能到达所有方格
void test4()
{
    test("Test4", 10, 1, 10, 10);
}

// 方格只有一列,机器人只能到达部分方格
void test5()
{
    test("Test5", 15, 100, 1, 79);
}

// 方格只有一列,机器人能到达所有方格
void test6()
{
    test("Test6", 15, 10, 1, 10);
}

// 方格只有一行一列
void test7()
{
    test("Test7", 15, 1, 1, 1);
}

// 方格只有一行一列
void test8()
{
    test("Test8", 0, 1, 1, 1);
}

// 机器人不能进入任意一个方格
void test9()
{
    test("Test9", -10, 10, 10, 0);
}

int main(int agrc, char* argv[])
{
    test1();
    test2();
    test3();
    test4();
    test5();
    test6();
    test7();
    test8();
    test9();

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值