第1题:鸡兔同笼
一个笼子里面关了鸡和兔子(鸡有2只脚,兔子有4只脚,没有例外)。已经知道了笼子里面脚的总数a,问笼子里面至少有多少只动物,至多有多少只动物。
时间限制:1000
内存限制:65536
输入
一行,一个正整数a (a < 32768)。
输出
一行,包含两个正整数,第一个是最少的动物数,第二个是最多的动物数,两个正整数用一个空格分开。 如果没有满足要求的答案,则输出两个0,中间用一个空格分开。
样例输入
20
样例输出
5 10
这个问题可以通过数学方法来解决。我们知道鸡有2只脚,兔子有4只脚,且没有例外。假设笼子里的动物数为x,则鸡的数量为y,兔子的数量为z。
根据题目条件,我们可以得到以下两个等式:
(1)2y + 4z = a (脚的总数为a)
(2)y + z = x (动物的总数为x)
我们需要求解的是最少和最多的动物数,即求解x的最小值和最大值。
最少动物数的情况下,我们假设所有的动物都是兔子,此时每只动物有4只脚。因此,脚的总数a的最小值必须是4的倍数。在这种情况下,鸡的数量y为0,兔子的数量z为a/4。
最多动物数的情况下,我们假设所有的动物都是鸡,此时每只动物有2只脚。因此,脚的总数a的最大值必须是2的倍数。在这种情况下,兔子的数量z为0,鸡的数量y为a/2。
综上所述,最少动物数为a/4,最多动物数为a/2。但是需要注意的是,最少和最多动物数必须是整数,且最少动物数不能大于最多动物数。
下面是使用 C 语言编写的解题代码:
#include <stdio.h>
int main() {
int a;
scanf("%d", &a);
int minAnimals = a / 4;
int maxAnimals = a / 2;
if (a % 4 != 0) {
minAnimals++;
}
if (minAnimals > maxAnimals) {
minAnimals = maxAnimals = 0;
}
printf("%d %d\n", minAnimals, maxAnimals);
return 0;
}
在上述代码中,我们首先读取输入的脚的总数 a
。然后,我们根据数学推导计算最少和最多的动物数,并将结果输出。
需要注意的是,我们在计算最少动物数时,如果 a
不能被4整除,需要将最少动物数加1,以确保最少动物数为整数。另外,如果最少动物数大于最多动物数,表示没有满足要求的答案,将最少和最多动物数都设置为0。
编译并运行上述的代码可以解决该问题。你可以使用 C 语言编译器将代码保存为 .c
文件,然后编译并运行该文件来获取结果。
第2题:猴子吃桃
海滩上有一堆桃子,N只猴子来分。第一只猴子把这堆桃子平均分为N份,多了一个,这只猴子把多的一个扔入海中,拿走了一份。第二只猴子接着把剩下的桃子平均分成N份,又多了一个,它同样把多的一个扔入海中,拿走了一份。第三、第四、……,第N只猴子仍是最终剩下的桃子分成N份,扔掉多了的一个,并拿走一份。
编写程序,输入猴子的数量N,输出海滩上最少的桃子数,使得每只猴子都可吃到桃子。
时间限制:3000
内存限制:65536
输入
一个整数N。
输出
输出当猴子数量为N时海滩上最少的桃子数。结果保证在int型范围内。
样例输入
2
样例输出
7
这个问题可以使用逆推的思路来解决。我们假设最后剩下的桃子数为x,根据题目描述,可以得到以下等式:
x = (N-1) * (x/N) - 1
根据上述等式,我们可以从最后一只猴子开始逆推,每次逆推得到的桃子数都是上一只猴子分完后剩下的桃子数。
下面是使用 C 语言编写的解题代码:
#include <stdio.h>
int findMinPeaches(int N) {
int peaches = N; // 假设最后剩下的桃子数为N
while (1) {
int total = peaches; // 当前剩下的桃子数
int i;
for (i = 0; i < N; i++) {
if (total % (N-1) != 0) {
// 无法平均分配,不满足条件,增加桃子数并重新开始逆推
peaches++;
break;
}
total = (N-1) * (total/N) - 1;
}
if (i == N) {
// 找到满足条件的最小桃子数
return peaches;
}
}
}
int main() {
int N;
scanf("%d", &N);
int minPeaches = findMinPeaches(N);
printf("%d\n", minPeaches);
return 0;
}
在上述代码中,我们定义了一个函数 findMinPeaches
来逆推找到满足条件的最小桃子数。在函数中,我们假设最后剩下的桃子数为N,然后从最后一只猴子开始逆推,每次逆推得到的桃子数都是上一只猴子分完后剩下的桃子数。我们使用一个循环来进行逆推,直到找到满足条件的最小桃子数。
在 main
函数中,我们读取输入的猴子数量 N
,然后调用 findMinPeaches
函数来计算最小桃子数,并将结果输出。
需要注意的是,该方法是通过逆推来找到最小桃子数的,因此在某些情况下可能会有一定的时间复杂度。对于较大的 N
值,可能需要较长的计算时间。
编译并运行上述的代码可以解决该问题。你可以使用 C 语言编译器将代码保存为 .c
文件,然后编译并运行该文件来获取结果。
第3题:扩号匹配问题
在某个字符串(长度不超过100)中有左括号、右括号和大小写字母;规定(与常见的算数式子一样)任何一个左括号都从内到外与在它右边且距离最近的右括号匹配。写一个程序,找到无法匹配的左括号和右括号,输出原来字符串,并在下一行标出不能匹配的括号。不能匹配的左括号用"$“标注,不能匹配的右括号用”?“标注.
时间限制:3000
内存限制:65536
输入
输入包括多组数据,每组数据一行,包含一个字符串,只包含左右括号和大小写字母,字符串长度不超过100
输出
对每组输出数据,输出两行,第一行包含原始输入字符,第二行由”$“,”?“和空格组成,”$“和”?"表示与之对应的左括号和右括号不能匹配。
样例输入
((ABCD(x)
)(rttyy())sss)(
样例输出
((ABCD(x)
$$
)(rttyy())sss)(
? ?$
这个问题可以使用栈来解决。我们可以遍历字符串中的每个字符,并将左括号入栈,当遇到右括号时,判断栈顶元素是否为左括号,如果是,则将栈顶元素出栈,表示匹配成功;如果不是,则将当前右括号标记为无法匹配的右括号。
在遍历完整个字符串后,栈中可能还有剩余的左括号,这些左括号都是无法匹配的左括号。
下面是使用 C 语言编写的解题代码:
#include <stdio.h>
#include <string.h>
#define MAX_SIZE 100
void printUnmatchedParentheses(char* str) {
int len = strlen(str);
int stack[MAX_SIZE]; // 用于存储左括号的栈
int top = -1; // 栈顶指针
for (int i = 0; i < len; i++) {
if (str[i] == '(') {
// 遇到左括号,入栈
stack[++top] = i;
} else if (str[i] == ')') {
// 遇到右括号
if (top >= 0 && str[stack[top]] == '(') {
// 栈不为空且栈顶元素为左括号,匹配成功,栈顶元素出栈
top--;
} else {
// 无法匹配的右括号
str[i] = '?';
}
}
}
while (top >= 0) {
// 未匹配的左括号
str[stack[top--]] = '$';
}
printf("%s\n", str);
for (int i = 0; i < len; i++) {
if (str[i] == '$' || str[i] == '?') {
printf("%c", str[i]);
} else {
printf(" ");
}
}
printf("\n");
}
int main() {
char str[MAX_SIZE];
while (scanf("%s", str) != EOF) {
printUnmatchedParentheses(str);
}
return 0;
}
在上述代码中,我们定义了一个函数 printUnmatchedParentheses
来打印无法匹配的括号。在函数中,我们使用一个栈来存储左括号的索引。遍历字符串中的每个字符,当遇到左括号时,将其索引入栈;当遇到右括号时,判断栈顶元素是否为左括号,如果是,则将栈顶元素出栈,表示匹配成功;如果不是,则将当前右括号标记为无法匹配的右括号。遍历完整个字符串后,栈中可能还有剩余的左括号,这些左括号都是无法匹配的左括号。
在 main
函数中,我们循环读取输入的字符串,并调用 printUnmatchedParentheses
函数来打印无法匹配的括号。
编译并运行上述的代码可以解决该问题。你可以使用 C 语言编译器将代码保存为 .c
文件,然后编译并运行该文件来获取结果。
第4题:上台阶
楼梯有n(100 > n > 0)阶台阶,上楼时可以一步上1阶,也可以一步上2阶,也可以一步上3阶,编程计算共有多少种不同的走法。
时间限制:1000
内存限制:65536
输入
输入的每一行包括一组测试数据,即为台阶数n。最后一行为0,表示测试结束。
输出
每一行输出对应一行输入的结果,即为走法的数目。
样例输入
1
2
3
4
0
样例输出
1
2
4
7
这个问题可以使用动态规划来解决。我们可以定义一个数组 dp
,其中 dp[i]
表示上 i
阶台阶的不同走法数量。根据题目描述,我们可以得到以下状态转移方程:
dp[i] = dp[i-1] + dp[i-2] + dp[i-3]
其中,dp[i-1]
表示从 i-1
阶走一步到达 i
阶的走法数量,dp[i-2]
表示从 i-2
阶走两步到达 i
阶的走法数量,dp[i-3]
表示从 i-3
阶走三步到达 i
阶的走法数量。因为每次可以选择走一步、两步或三步,所以到达 i
阶的走法数量等于到达 i-1
阶、i-2
阶和 i-3
阶的走法数量之和。
下面是使用 C 语言编写的解题代码:
#include <stdio.h>
#define MAX_SIZE 101
long long countWays(int n) {
long long dp[MAX_SIZE];
// 初始化前三个台阶的走法数量
dp[0] = 0;
dp[1] = 1;
dp[2] = 2;
dp[3] = 4;
// 计算从第4个台阶开始的走法数量
for (int i = 4; i <= n; i++) {
dp[i] = dp[i-1] + dp[i-2] + dp[i-3];
}
return dp[n];
}
int main() {
int n;
while (1) {
scanf("%d", &n);
if (n == 0) {
break;
}
long long ways = countWays(n);
printf("%lld\n", ways);
}
return 0;
}
在上述代码中,我们定义了一个函数 countWays
来计算上 n
阶台阶的不同走法数量。我们使用一个数组 dp
来存储走法数量,初始时将前三个台阶的走法数量进行初始化,然后从第4个台阶开始计算每个台阶的走法数量,直到达到目标台阶 n
。
在 main
函数中,我们循环读取输入的台阶数 n
,如果输入的 n
为 0,则表示测试结束,退出循环。否则,调用 countWays
函数来计算不同走法数量,并将结果输出。
需要注意的是,题目要求的不同走法数量可能非常大,超过 int
类型的范围,因此我们使用了 long long
类型来存储结果。
编译并运行上述的代码可以解决该问题。你可以使用 C 语言编译器将代码保存为 .c
文件,然后编译并运行该文件来获取结果。
第5题:田忌赛马
在田忌赛马的故事中,孙膑用自己的下等马对战对手的上等马,自己上等马对阵对手的中等马,自己的中等马对阵对手的下等马,从而赢得了胜利。现在即将进行的是N匹马的赛马比赛。双方队伍的马各分为N等。已知只有当我方马的等级比对方马等级高X等以上(包含X)时,我方才可以取得这场比赛的胜利。如果在N场比赛中我方的胜场数大于对方,则我方取得最终的胜利。现在已知对方这N场比赛的出战方案,请计算所有令我方最终获胜的出战方案。
时间限制:1000
内存限制:65536
输入
第一行两个整数,N和X。N≤9, 0 ≤ X < N。 第二行N个正整数,A(1)…A(N)。A(i)表示第i场比赛对方马的等级,1≤i≤N。等级越高越强
输出
按字典序输出所有我方最终获胜的方案,每个方案一行。每行是N个正整数,第i个数表示我方第i场比赛马的等级。
样例输入
样例1输入
3 1
3 2 1
样例2输入
3 0
3 1 2
样例输出
样例1输出
1 3 2
样例2输出
1 2 3
1 3 2
2 1 3
3 1 2
3 2 1
这个问题可以使用回溯法来解决。我们可以使用递归函数来生成所有可能的出战方案,并按字典序输出满足条件的方案。
具体步骤如下:
-
创建一个数组
result
用于存储满足条件的出战方案。 -
创建一个数组
visited
用于标记每个马是否已经被选中。 -
创建一个递归函数
backtrack
,该函数接收当前比赛的编号index
,当前已选中的马的等级数组current
,以及对方马的等级数组opponent
。 -
在递归函数中,首先判断是否已经完成了所有比赛,即
index
是否等于N
。如果是,则将current
添加到result
中。 -
否则,对于当前比赛的对方马等级
opponent[index]
,从高等级到低等级依次尝试选择我方马的等级。 -
遍历我方马的等级时,根据题目要求判断是否满足条件,如果满足则将该马的等级添加到
current
中,并将对应的visited
标记为已访问。 -
在递归函数中调用下一场比赛,即递归调用
backtrack(index + 1, current, opponent)
。 -
在递归调用返回后,将当前选择的马的等级从
current
中移除,并将对应的visited
标记为未访问,以便尝试其他选择。 -
在主函数中,按字典序输出
result
中的所有方案。
下面是使用 C 语言编写的解题代码:
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#define MAX_SIZE 9
void backtrack(int index, int N, int X, int opponent[], int current[], bool visited[], int result[][MAX_SIZE], int* count) {
if (index == N) {
memcpy(result[*count], current, sizeof(int) * N);
(*count)++;
return;
}
for (int i = N - 1; i >= 0; i--) {
if (!visited[i] && current[index - X] > opponent[index]) {
visited[i] = true;
current[index] = i + 1;
backtrack(index + 1, N, X, opponent, current, visited, result, count);
visited[i] = false;
}
}
}
int main() {
int N, X;
scanf("%d %d", &N, &X);
int opponent[MAX_SIZE];
for (int i = 0; i < N; i++) {
scanf("%d", &opponent[i]);
}
int result[MAX_SIZE * MAX_SIZE][MAX_SIZE];
int count = 0;
int current[MAX_SIZE];
bool visited[MAX_SIZE] = { false };
backtrack(0, N, X, opponent, current, visited, result, &count);
for (int i = 0; i < count; i++) {
for (int j = 0; j < N; j++) {
printf("%d ", result[i][j]);
}
printf("\n");
}
return 0;
}
在上述代码中,我们使用了一个二维数组 result
来存储满足条件的出战方案,其中每一行表示一个方案,每一列表示我方对应比赛的马的等级。我们还定义了一个整数变量 count
来记录满足条件的方案数量。
在 backtrack
函数中,我们首先判断是否已经完成了所有比赛,如果是,则将当前方案 current
添加到 result
中。否则,对于当前比赛的对方马等级 opponent[index]
,从高等级到低等级依次尝试选择我方马的等级。遍历我方马的等级时,根据题目要求判断是否满足条件,如果满足则将该马的等级添加到 current
中,并将对应的 visited
标记为已访问。然后递归调用下一场比赛,即 backtrack(index + 1, current, opponent)
。在递归调用返回后,将当前选择的马的等级从 current
中移除,并将对应的 visited
标记为未访问,以便尝试其他选择。
在主函数中,我们首先读取输入的比赛信息,然后调用 backtrack
函数来生成所有满足条件的方案。最后,按字典序输出 result
中的所有方案。
编译并运行上述的代码可以解决该问题。你可以使用 C 语言编译器将代码保存为 .c
文件,然后编译并运行该文件来获取结果。