第1题:最佳路径
如下所示的由正整数数字构成的三角形:
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。你的任务就是求出最佳路径上的数字之和。
注意:路径上的每一步只能从一个数走到下一层上和它最近的下边(正下方)的数或者右边(右下方)的数。
时间限制:1000
内存限制:65536
输入
第一行为三角形高度100>=h>=1,同时也是最底层边的数字的数目。 从第二行开始,每行为三角形相应行的数字,中间用空格分隔。
输出
最佳路径的长度数值。
样例输入
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
样例输出
30
以下是解决该问题的C语言代码实现:
#include <stdio.h>
int maxPathSum(int triangle[][100], int N) {
int dp[100][100] = {
0};
// 初始化最底层的dp值为三角形最底层的值
for (int i = 0; i < N; i++) {
dp[N - 1][i] = triangle[N - 1][i];
}
// 从倒数第二层开始迭代计算dp值
for (int i = N - 2; i >= 0; i--) {
for (int j = 0; j <= i; j++) {
dp[i][j] = triangle[i][j] + (dp[i + 1][j] > dp[i + 1][j + 1] ? dp[i + 1][j] : dp[i + 1][j + 1]);
}
}
return dp[0][0];
}
int main() {
int N;
scanf("%d", &N);
int triangle[100][100];
for (int i = 0; i < N; i++) {
for (int j = 0; j <= i; j++) {
scanf("%d", &triangle[i][j]);
}
}
int maxSum = maxPathSum(triangle, N);
printf("%d\n", maxSum);
return 0;
}
该代码使用动态规划的思想来解决问题。定义一个dp数组,其中dp[i][j]表示从三角形顶部到达位置(i, j)的最佳路径的数字之和。
通过迭代计算dp数组,同时返回dp[0][0]作为结果。
首先,将dp数组的最底层初始化为三角形最底层的值,即dp[N-1][i] = triangle[N-1][i]。
然后,从倒数第二层开始迭代计算dp数组。对于位置(i, j),dp[i][j]的值可以通过以下方式计算:
- dp[i][j] = triangle[i][j] + max(dp[i+1][j], dp[i+1][j+1]),即当前位置的值加上下一层相邻位置的最佳路径的数字之和。
最后,返回dp[0][0]作为结果,即最佳路径的数字之和。
第2题:数字构造
火山宝打算造一个 n 位的十进制数字出来。
对于 1 到 n 中的每一个 i,火山宝可以从 xi,1, …, xi,ki 这 ki 个 0-9 的数字中选择一个作为 ai。
在选择结束后,a1a2…an 形成了一个 n 位的十进制数——这就是火山宝造出来的数。
你需要帮火山宝计算他能造出的数中,有多少个是 3 的倍数。
时间限制:1000
内存限制:65536
输入
第一行输入一个整数 n(1 ≤ n ≤ 18),表示数字的位数。 接下来 n 行,每行第一个整数 ki (1 ≤ ki ≤ 10),表示第 i 中候选的数字数量。接着是 ki 个两两不同的 0-9 范围内的数字 xi,1, …, xi,ki。 输入保证 0 不是第一位的可选项。
输出
你需要输出一行一个整数,表示火山宝能造出的数字中,3 的倍数的数量。
样例输入
样例输入1:
2
5 5 6 7 8 9
5 0 1 2 3 4
样例输入2:
5
9 1 2 3 4 5 6 7 8 9
10 0 1 2 3 4 5 6 7 8 9
10 0 1 2 3 4 5 6 7 8 9
10 0 1 2 3 4 5 6 7 8 9
10 0 1 2 3 4 5 6 7 8 9
样例输出
样例输出1:
9
样例输出2:
30000
提示
样例1能造出来的 3 的倍数有 51, 54,60,63,72,81,84,90, 93。
要解决这个问题,可以使用回溯法来生成所有可能的数字,并检查每个数字是否是3的倍数。
以下是使用C语言实现的代码:
#include <stdio.h>
#include <stdbool.h>
int count = 0;
bool isMultipleOfThree(int num) {
return num % 3 == 0;
}
void generateNumbers(int digits, int candidates[][10], int currentDigit, int currentNumber) {
if (currentDigit > digits) {
if (isMultipleOfThree(currentNumber)) {
count++;
}
return;
}
for (int i = 0; i < candidates[currentDigit][0]; i++) {
generateNumbers(digits, candidates, currentDigit + 1, currentNumber * 10 + candidates[currentDigit][i + 1]);
}
}
int main() {
int n;
scanf("%d", &n);
int candidates[18][10];
for (int i = 1; i <= n; i++) {
scanf("%d", &candidates[i][0]);
for (int j = 1; j <= candidates[i][0]; j++) {
scanf("%d", &candidates[i][j]);
}
}
generateNumbers(n, candidates, 1, 0);
printf("%d\n", count);
return 0;
}
该代码通过递归的方式生成所有可能的数字。对于每一位,根据候选数字的数量进行循环,并将当前位的数字与之前的数字构成一个新的数。
在递归的过程中,如果生成的数字位数超过了给定的位数,则检查该数字是否是3的倍数。如果是,计数器count加1。
最后,输出计数器count的值,即火山宝能造出的数字中3的倍数的数量。
第3题:奶牛散步
从一个无限大的矩阵的中心点出发,一步只能向右走、向上走或向左走。恰好走N步且不经过已走的点共有多少种走法?
输入
一个数字,代表N,N<=1000
输出
输出有多少方案数模12345
样例输入
2
样例输出
7
要解决这个问题,可以使用动态规划的方法来计算不同步数下的方案数。
以下是使用C语言实现的代码:
#include <stdio.h>
int countWalks(int N) {
int dp[2][3] = {
0}; // 使用滚动数组保存状态
dp[1][1] = 1; // 初始位置
for (int step = 1; step <= N; step++) {
int curr = step % 2; // 当前行的索引
int prev = (step - 1) % 2; // 上一行的索引
dp[curr][0] = (dp[prev][1] + dp[prev][2]) % 12345; // 向右走
dp[curr][1] = (dp[prev][0] + dp[prev][2]) % 12345; // 向上走
dp[curr][2] = (dp[prev][0] + dp[prev][1] + dp[prev][2]) % 12345; // 向左走
}
return dp[N % 2][0] + dp[N % 2][1] + dp[N % 2][2];
}
int main() {
int N;
scanf("%d", &N);
int numWalks = countWalks(N);
printf("%d\n", numWalks);
return 0;
}
该代码使用滚动数组来保存状态,使用dp[i][j]表示走i步到达位置j的方案数。
初始时,将dp[1][1]设置为1,表示初始位置。
然后,从第2步开始迭代计算dp数组。对于每一步,根据上一步的方案数计算当前步的方案数:
-
向右走:dp[curr][0] = (dp[prev][1] + dp[prev][2]) % 12345
-
向上走:dp[curr][1] = (dp[prev][0] + dp[prev][2]) % 12345
-
向左走:dp[curr][2] = (dp[prev][0] + dp[prev][1] + dp[prev][2]) % 12345
最后,返回dp[N % 2][0] + dp[N % 2][1] + dp[N % 2][2]作为结果,即走N步的方案数。
希望以上代码能帮助你解决问题!
第4题:吃奶酪
Jerry准备偷吃Tom的奶酪。所有的奶酪排成了一条直线,每块奶酪都有不同的美味程度。然而,如果有相邻两块奶酪都被Jerry偷吃,Tom就会发现这一点并迅速抓住Jerry。Jerry当然希望在不被Tom发现的条件下吃到的奶酪美味度总和最大。当然,他也可以选择一块奶酪都不吃。请你帮助他规划一下偷吃的方案,告诉他最多能偷吃到多少的美味度吧。
时间限制:1000
内存限制:65536
输入
第一行一个整数T (T<=100),表示测试数据组数。 接下来,每组测试数据包含两行。其中,第一行一个整数n (1 <= n <= 100,000) ,表示奶酪的数量;第二行n个整数,表示这一排直线上奶酪的美味程度,请注意,美味度保证能够被int类型存储,且可能是负数。
输出
对于每组测试数据,输出一个整数,表示Jerry可以吃到的最大美味度总和。请注意,美味度总和可能超过int存储范围
样例输入
2
4
1 2 3 1
5
2 7 9 3 1
样例输出
4
12
要解决这个问题,可以使用动态规划的方法来计算最大美味度总和。
以下是使用C语言实现的代码:
#include <stdio.h>
int max(int a, int b) {
return (a > b) ? a : b;
}
long long int maxCheese(int n, int cheese[]) {
long long int dp[100001] = {
0};
dp[0] = cheese[0];
dp[1] = max(cheese[0], cheese[1]);
for (int i = 2; i < n; i++) {
dp[i] = max(dp[i - 1], dp[i - 2] + cheese[i]);
}
return dp[n - 1];
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
int n;
scanf("%d", &n);
int cheese[100000];
for (int i = 0; i < n; i++) {
scanf("%d", &cheese[i]);
}
long long int maxSum = maxCheese(n, cheese);
printf("%lld\n", maxSum);
}
return 0;
}
该代码使用动态规划来计算最大美味度总和。使用dp数组保存到达每个奶酪位置时的最大美味度总和。
初始时,dp[0]等于第一块奶酪的美味度,dp[1]等于第一块和第二块奶酪中较大的美味度。
然后,从第三块奶酪开始迭代计算dp数组。对于每个位置i,可以选择不偷第i块奶酪(保持dp[i-1]不变)或偷第i块奶酪(dp[i] = dp[i-2] + cheese[i])中较大的美味度总和。
最后,返回dp[n-1]作为结果,即Jerry可以吃到的最大美味度总和。
希望以上代码能帮助你解决问题!