每日一练24&&25——年终奖&&迷宫问题(难)&&星际密码(易错)&&数根(接收数据的方法)


年终奖

题目链接:

思路:

本题需要使用动态规划求解。
定义f(i,j)表示从左上角走到坐标(i,j)处能获得的最大奖励。

搜索所有从左上角走到右下角的路径,找到最优路径。
通俗的来讲对于f(2,1),要算最大,那么就要选择从上面来的奖励更大还是从左面来的奖励更大。

在这里插入图片描述

对于任意f(i,j)分三种情况:

  • 第一列:对于第一列的所有坐标,只能选择从上面来的奖励,然后再加上自己方格中的奖励,所以f(i, 0) = f(i-1, 0) + board(i, 0)
  • 第一行:对于第一行的所有坐标,只能选择从左面来的奖励,然后再加上自己方格中的奖励,所以f(0,j) = f(0, j - 1) + b(0, j)
  • 其它位置:不是第一行也不是第一列,就要选择是从上面来的奖励更大还是从左面来的奖励更大,然后再加上自己方格中的奖励,f(i, j) = max{f(i-1, j), f(i, j - 1)} + board(i, j)

最后右下角的值即为所求答案。

代码:

class Bonus {
  public:
    int getMost(vector<vector<int> > board) {
        // write code here
        vector<vector<int>> value(board.size(), vector<int>(board[0].size(), 0));
        value[0][0] = board[0][0];

        int row = board.size();
        int col = board[0].size();
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                if (i == 0 && j == 0)
                    continue;
                if (i == 0)
                    value[i][j] = value[i][j - 1] + board[i][j];

                else if (j == 0)
                    value[i][j] = value[i - 1][j] + board[i][j];
                else
                    value[i][j] = max(value[i - 1][j], value[i][j - 1]) + board[i][j];
            }
        }
        return value[row - 1][col - 1];
    }
};


迷宫问题

题目链接:

思路:

本题可用回溯法求解
具体步骤为:

  1. 首先将当前点加入(push_back)路径,并设置为已走,封死当前点,不能再走此点。
  2. 判断当前点是否为出口,是则保存结果,再看是否比最短路径还要短,如果是,更新最短路径;
  3. 依次判断当前点的上、下、左、右四个点是否可走,
  • 如果可走,则递归走这四个方向;
  • 如果不可走,则当前点pop_back 临时路径,设置为此点可走

代码:

#include<iostream>
#include<vector>
using namespace std;

//全局的变量
vector<vector<int>> vv;//迷宫数组
vector<vector<int>> best_path;//最短路径
vector<vector<int>> tmp_path;//临时路径

void FindPath(int row, int col) {
    int ROW = vv.size();
    int COL = vv[0].size();

    vv[row][col] = 1;//代表走过,然后封死,不能再走此路
    tmp_path.push_back({ row,col });


    if (row == ROW - 1 && col == COL - 1)
    {
        if (best_path.empty() || best_path.size() > tmp_path.size())
        {
            best_path = tmp_path;
        }
    }
	
	//向上下左右走
    //往上走
    if (row - 1 >= 0 && vv[row - 1][col]==0)
    {
        FindPath(row - 1, col);
    }

    //往下走
    if (row + 1 < ROW && vv[row + 1][col] == 0)///犯错之处
    {
        FindPath(row + 1, col);
    }
    //往左走
    if (col - 1 >= 0 && vv[row][col - 1] == 0)
    {
        FindPath(row, col - 1);
    }
    //往右走
    if (col + 1 < COL && vv[row][col + 1] == 0)//犯错之处
    {
        FindPath(row, col + 1);
    }
    //能来下面说明上面都没走通,就恢复路径
    vv[row][col] = 0;
    tmp_path.pop_back();

}


int main() {
    int N, M;
    cin >> N >> M;

    vv = vector<vector<int>>(N, vector<int>(M, 0));//匿名对象赋值

    for (int row = 0; row < N; row++) {
        for (int col = 0; col < M; col++) {
            cin >> vv[row][col];
        }
    }

    FindPath(0, 0);

    for (int i = 0; i < best_path.size(); i++)
    {
        cout << "(" << best_path[i][0] << "," << best_path[i][1] << ")" << endl;
    }

    return 0;
}


星际密码

题目链接:

思路:

这个题目首先需要明确矩阵是固定的,其次是矩阵相乘的方法
矩阵相乘公式

|a1 a2| * |c1 c2| = |a1c1 + a2d1 a1c2 + a2d2|
|b1 b2|   |d1 d2|   |b1c1 + b2d1 b1d2 + b2d2|

矩阵是

|1 1|^2 = |1 1|*|1 1|=|2 1|
|1 0|     |1 0| |1 0| |1 1|

n的取值:1 2 3 4 5 6 …
左上角值:1 2 3 5 8 13 …
是一个变式的斐波那契初始化斐波那契数列,每次获取对应数据,打印最后4位即可。
不能认为到这里就完了,题目最高要求第10000个斐波那契数。
直接算?
43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875
这是1000位的斐波那契数列的值,十进制足足200多位,long long也才是2的64次方
!!!!!!!!!!!!!!
天文数字,这里就要抛开传统的递归方法,使用一个数组来依次计算每个斐波那契数的后四位即可,保留后四位可以用%10000

代码:

#include <iostream>
#include <vector>
std::vector<int> a = {1, 1};

void data_init() {
    int i;
    for (i = 2; i < 10005; i++) {
        a.push_back((a[i - 1] + a[i - 2]) % 10000);
    }
}

int main() {
    int n, t;
    data_init();
    while (std::cin >> n) {
        while (n--) {
            std::cin >> t;
            printf("%04d", a[t]);//不足4位补0
        }
        printf("\n");

    }
    return 0;
}

数根

题目链接:

思路:

这个题目很容易理解,对于数字的每一位进行相加直到不大于9为止即可
但是这里涉及到的数字又是非常的大!

  1. 为了防止数字过大,这里采用字符串的形式来接收各个数字,并且每位求和。瞬间非常大的数字就被化解。
  2. 接下来,都能想到,就是循环对大于9的数字进行对10取余和整除操作,将结果进行相加得到树根。

代码:

#include <iostream>
#include <string>
int numRoot(int num) {
    int nroot = 0;
    while (num > 0) {
        /*每次只获取个位数字---个位数+十位数*/
        nroot += num % 10;
        num /= 10;
    }
    while (nroot > 9) {
        nroot = numRoot(nroot);
    }
    return nroot;
}

int main() {
    std::string origin;
    while (std::cin >> origin) {
        int sum = 0;
        //先将每一位进行相加得到总和,防止数字过大
        for (int i = 0; i < origin.length(); i++) {
            sum += origin[i] - '0';
        }
        //对总和求树根
        std::cout << numRoot(sum) << std::endl;
    }
    return 0;
}

end

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

有效的放假者

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

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

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

打赏作者

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

抵扣说明:

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

余额充值