年终奖
思路:
本题需要使用动态规划求解。
定义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];
}
};
迷宫问题
思路:
本题可用回溯法求解
具体步骤为:
- 首先将当前点加入(push_back)路径,并设置为已走,封死当前点,不能再走此点。
- 判断当前点是否为出口,是则保存结果,再看是否比最短路径还要短,如果是,更新最短路径;
- 依次判断当前点的上、下、左、右四个点是否可走,
- 如果可走,则递归走这四个方向;
- 如果不可走,则当前点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为止即可
但是这里涉及到的数字又是非常的大!
- 为了防止数字过大,这里采用字符串的形式来接收各个数字,并且每位求和。瞬间非常大的数字就被化解。
- 接下来,都能想到,就是循环对大于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