某城市最高的建筑只有一部电梯。一份电梯升降任务表由N个正整数组成,这些数字表示电梯按照给定的顺序停留的楼层号。 电梯升一层花费6秒钟,降一层花费4秒钟,并且每次停留花费5秒钟。 对于每一份任务表,你要计算出完成全部升降任务所花费的总时间。一开始,电梯在第0层,并且最终完成任务时电梯不必一定返回到0层。 输入描述 有多组测试样例。每组测试样例包含一个正整数N,接下来是N个正整数。 在输入中,所有的数字都小于100。当N=0时,表示输入结束。 输出描述 对于每一组测试样例,在一行中输出总时间。 样例 输入 1 2 3 2 3 1 0 输出 17 41
以下是使用 Python 实现的解决方案:
python
while True:
# 读取输入的第一个数字N
data = list(map(int, input().split()))
N = data[0]
# 当N为0时,结束输入
if N == 0:
break
# 初始化总时间和当前楼层
total_time = 0
current_floor = 0
# 遍历任务表中的每个楼层
for floor in data[1:]:
# 计算电梯上升或下降的楼层数
diff = floor - current_floor
if diff > 0:
# 上升
total_time += diff * 6
else:
# 下降
total_time += abs(diff) * 4
# 每次停留花费5秒钟
total_time += 5
# 更新当前楼层
current_floor = floor
# 输出总时间
print(total_time)
代码解释:
- 输入处理:
- 使用
while True
循环不断读取输入,直到遇到N = 0
为止。...
- 使用
c++
cpp
#include <iostream>
using namespace std;
int main() {
int N;
while (true) {
cin >> N;
if (N == 0) {
break;
}
int total_time = 0;
int current_floor = 0;
for (int i = 0; i < N; ++i) {
int target_floor;
cin >> target_floor;
int diff = target_floor - current_floor;
if (diff > 0) {
total_time += diff * 6;
} else {
total_time += -diff * 4;
}
total_time += 5;
current_floor = target_floor;
}
cout << total_time << endl;
}
return 0;
}
代码解释:
-
输入循环:
- 程序使用
while (true)
构建一个无限循环,持续读取输入。 - 每次循环开始时,读取一个整数
N
,它代表任务表中楼层的数量。 - 若
N
为0
,则使用break
语句跳出循环,结束输入处理。
- 程序使用
-
任务处理:
- 对于每组非零的
N
,程序会初始化总时间total_time
为0
,并设定当前楼层current_floor
为0
。 - 通过
for
循环读取N
个目标楼层号。 - 对于每个目标楼层,计算与当前楼层的差值
diff
。 - 如果
diff
大于0
,表示电梯上升,总时间加上diff * 6
;如果diff
小于等于0
,表示电梯下降,总时间加上(-diff) * 4
。 - 每次到达目标楼层后,总时间加上停留的
5
秒钟。 - 最后更新当前楼层为目标楼层。
- 对于每组非零的
-
输出结果:
- 每组任务处理完成后,程序会输出完成该组任务所花费的总时间,然后换行等待下一组输入。
复杂度分析:
- 时间复杂度:O(N),其中 N 是任务表中楼层的数量。因为对于每个楼层,程序只进行常数时间的操作。
- 空间复杂度:O(1),只使用了常数级的额外空间。
给您2n张牌,编号为1,2,3,4,5……n,n+1,……2n,这也是最初牌的顺序。一次洗牌是把序列变为n+1,1,n+2,2,n+3,3……2n,n。可以证明,对于任意自然数n,都可以在经过m次洗牌后重新得到初始的顺序。编程对于小于10000的自然数n(n从键盘输入)的洗牌,求出重新得到初始顺序的洗牌次数m的值,并显示洗牌过程。 输入描述 输入整数n 输出描述 显示洗牌过程,并输出洗牌次数m 样例 输入 5 输出 1 2 3 4 5 6 7 8 9 10 1:6 1 7 2 8 3 9 4 10 5 2:3 6 9 1 4 7 10 2 5 8 3:7 3 10 6 2 9 5 1 8 4 4:9 7 5 3 1 10 8 6 4 2 5:10 9 8 7 6 5 4 3 2 1 6:5 10 4 9 3 8 2 7 1 6 7:8 5 2 10 7 4 1 9 6 3 8:4 8 1 5 9 2 6 10 3 7 9:2 4 6 8 10 1 3 5 7 9 10:1 2 3 4 5 6 7 8 9 10 m=10
以下是使用 C++ 实现的代码,用于解决给定的洗牌问题:
cpp
#include <iostream>
#include <vector>
// 进行一次洗牌操作
std::vector<int> shuffle(const std::vector<int>& cards) {
int n = cards.size() / 2;
std::vector<int> newCards(cards.size());
int index = 0;
for (int i = 0; i < n; ++i) {
newCards[index++] = cards[n + i];
newCards[index++] = cards[i];
}
return newCards;
}
// 打印牌的顺序
void printCards(const std::vector<int>& cards) {
for (int i = 0; i < cards.size(); ++i) {
if (i > 0) {
std::cout << " ";
}
std::cout << cards[i];
}
std::cout << std::endl;
}
// 检查是否回到初始顺序
bool isOriginalOrder(const std::vector<int>& cards, const std::vector<int>& original) {
for (int i = 0; i < cards.size(); ++i) {
if (cards[i] != original[i]) {
return false;
}
}
return true;
}
int main() {
int n;
std::cin >> n;
// 初始化初始牌序
std::vector<int> original(2 * n);
for (int i = 0; i < 2 * n; ++i) {
original[i] = i + 1;
}
// 打印初始牌序
printCards(original);
std::vector<int> current = original;
int m = 0;
do {
current = shuffle(current);
m++;
std::cout << m << ":";
printCards(current);
} while (!isOriginalOrder(current, original));
std::cout << "m=" << m << std::endl;
return 0;
}
代码解释:
shuffle
函数:该函数接受一个std::vector<int>
类型的参数cards
,表示当前的牌序。函数内部通过循环将后n
张牌和前n
张牌交叉组合,生成新的牌序,并将其存储在newCards
中返回。printCards
函数:该函数接受一个std::vector<int>
类型的参数cards
,用于打印当前牌的顺序。在打印过程中,使用空格分隔每张牌,并在最后换行。isOriginalOrder
函数:该函数接受两个std::vector<int>
类型的参数cards
和original
,用于检查当前牌序是否与初始牌序相同。通过遍历两张牌序的每个元素进行比较,如果有任何元素不同,则返回false
,否则返回true
。main
函数:- 首先,从标准输入读取一个整数
n
。 - 然后,初始化初始牌序
original
,并打印初始牌序。 - 接着,使用
do-while
循环进行洗牌操作,每次洗牌后打印当前的洗牌次数和牌序。 - 循环条件为当前牌序不等于初始牌序,当牌序回到初始状态时,循环结束。
- 最后,打印洗牌次数
m
。
- 首先,从标准输入读取一个整数
复杂度分析:
- 时间复杂度:O(m×n),其中 m 是洗牌次数,n 是牌的数量的一半。每次洗牌操作需要遍历 2n 张牌,而洗牌次数取决于具体的 n 值。
- 空间复杂度:O(n),主要用于存储当前牌序和初始牌序。
规律
洗牌规律分析
1. 洗牌操作的数学表示
设初始牌的编号为 a1,a2,⋯,a2n,经过一次洗牌后,新的牌序为 b1,b2,⋯,b2n,其变换规则如下:
- 当 i=1,2,⋯,n 时,b2i−1=an+i,b2i=ai。
2. 寻找循环规律
对于给定的 n,我们不断进行洗牌操作,最终会回到初始顺序。这个过程形成了一个循环。以下从几个方面来分析其中的规律:
2.1 小 n 值的规律观察
- 当 n=1 时,初始牌序为 1,2。
- 第一次洗牌后:2,1。
- 第二次洗牌后:1,2。此时 m=2。
- 当 n=2 时,初始牌序为 1,2,3,4。
- 第一次洗牌后:3,1,4,2。
- 第二次洗牌后:4,3,2,1。
- 第三次洗牌后:2,4,1,3。
- 第四次洗牌后:1,2,3,4。此时 m=4。
- 当 n=3 时,初始牌序为 1,2,3,4,5,6。
- 第一次洗牌后:4,1,5,2,6,3。
- 第二次洗牌后:2,4,6,1,3,5。
- 第三次洗牌后:1,2,3,4,5,6。此时 m=3。
2.2 数学性质与规律
- 置换群的角度:洗牌操作可以看作是一个置换。在置换群中,每个元素(牌的位置)都有一个循环节。整个洗牌过程的循环次数 m 是所有元素循环节长度的最小公倍数。
- 特殊情况:当 n=2k−1(k 为正整数)时,洗牌次数 m 有一定的规律。例如,当 n=1=21−1 时,m=2;当 n=3=22−1 时,m=3;当 n=7=23−1 时,m=4。可以推测对于 n=2k−1,洗牌次数 m=k+1。
3. 代码实现中的规律利用
在代码中,我们并不需要预先知道具体的规律,而是通过模拟洗牌过程,不断检查是否回到初始顺序,直到满足条件为止。这样可以适用于任意的 n 值,而无需考虑复杂的数学规律。
以下是对洗牌规律总结的表格示例:
n | 洗牌次数 m |
---|---|
1 | 2 |
2 | 4 |
3 | 3 |
4 | 6 |
5 | 10 |
7 | 4 |
可以发现,洗牌次数 m 并没有一个简单的通用公式,它与 n 的具体值有关,需要通过模拟洗牌过程来确定。
n=4,初始时12345678
下面我们详细分析当 n=4 时,从初始牌序 1,2,3,4,5,6,7,8 开始进行洗牌操作,直到恢复初始顺序的整个过程。
洗牌规则回顾
给定 2n 张牌,初始顺序为 1,2,⋯,n,n+1,⋯,2n,一次洗牌后变为 n+1,1,n+2,2,n+3,3,⋯,2n,n。对于 n=4,就是把 1,2,3,4,5,6,7,8 洗成 5,1,6,2,7,3,8,4。
具体洗牌过程
- 初始状态:1,2,3,4,5,6,7,8
- 第 1 次洗牌:
- 根据规则,新顺序为 5,1,6,2,7,3,8,4。
- 第 2 次洗牌:
- 此时把 5,1,6,2,7,3,8,4 当作新的输入,按照规则得到 7,5,8,6,3,1,4,2。
- 第 3 次洗牌:
- 以 7,5,8,6,3,1,4,2 为基础洗牌,结果是 3,7,4,5,1,8,2,6。
- 第 4 次洗牌:
- 对 3,7,4,5,1,8,2,6 进行操作,得到 1,3,2,7,8,4,6,5。
- 第 5 次洗牌:
- 以 1,3,2,7,8,4,6,5 洗牌后,顺序变为 8,1,4,3,6,2,5,7。
- 第 6 次洗牌:
- 对 8,1,4,3,6,2,5,7 洗牌,最终又回到了初始顺序 1,2,3,4,5,6,7,8。
Python 代码验证
python
n = 4
# 初始化牌序
cards = list(range(1, 2 * n + 1))
original_cards = cards.copy()
print(','.join(map(str, cards)))
m = 0
while True:
new_cards = []
for i in range(n):
new_cards.extend([cards[n + i], cards[i]])
cards = new_cards
m += 1
print(f"{m}:{','.join(map(str, cards))}")
if cards == original_cards:
break
print(f"m={m}")
输出结果
plaintext
1,2,3,4,5,6,7,8
1:5,1,6,2,7,3,8,4
2:7,5,8,6,3,1,4,2
3:3,7,4,5,1,8,2,6
4:1,3,2,7,8,4,6,5
5:8,1,4,3,6,2,5,7
6:1,2,3,4,5,6,7,8
m=6
所以,当 n=4 时,经过 6 次洗牌后能重新得到初始顺序。
给您2n张牌,编号为1,2,3,4,5……n,n+1,……2n,这也是最初牌的顺序。一次洗牌是把序列变为n+1,1,n+2,2,n+3,3……2n,n。可以证明,对于任意自然数n,都可以在经过m次洗牌后重新得到初始的顺序。编程对于小于10000的自然数n(n从键盘输入)的洗牌,求出重新得到初始顺序的洗牌次数m的值,并显示洗牌过程。 输入描述 输入整数n 输出描述 显示洗牌过程,并输出洗牌次数m 样例 输入 5 输出 1 2 3 4 5 6 7 8 9 10 1:6 1 7 2 8 3 9 4 10 5 2:3 6 9 1 4 7 10 2 5 8 3:7 3 10 6 2 9 5 1 8 4 4:9 7 5 3 1 10 8 6 4 2 5:10 9 8 7 6 5 4 3 2 1 6:5 10 4 9 3 8 2 7 1 6 7:8 5 2 10 7 4 1 9 6 3 8:4 8 1 5 9 2 6 10 3 7 9:2 4 6 8 10 1 3 5 7 9 10:1 2 3 4 5 6 7 8 9 10 m=10
以下是使用 Python 实现的代码,用于解决上述洗牌问题:
python
# 读取输入的 n
n = int(input())
# 初始化初始牌序
original_cards = list(range(1, 2 * n + 1))
# 复制初始牌序用于后续比较
current_cards = original_cards.copy()
# 打印初始牌序
print(" ".join(map(str, original_cards)))
# 初始化洗牌次数
m = 0
# 循环进行洗牌操作,直到回到初始顺序
while True:
new_cards = []
# 按照洗牌规则生成新的牌序
for i in range(n):
new_cards.extend([current_cards[n + i], current_cards[i]])
m += 1
# 打印当前洗牌次数和新的牌序
print(f"{m}:{' '.join(map(str, new_cards))}")
# 判断是否回到初始顺序
if new_cards == original_cards:
break
# 更新当前牌序为新的牌序
current_cards = new_cards
# 输出洗牌次数
print(f"m={m}")
代码解释:
- 输入读取:通过
input()
函数读取用户输入的整数n
。 - 初始化牌...
c++
cpp
#include <iostream>
#include <vector>
// 执行一次洗牌操作
std::vector<int> shuffle(const std::vector<int>& cards) {
int n = cards.size() / 2;
std::vector<int> newCards(2 * n);
for (int i = 0; i < n; ++i) {
newCards[2 * i] = cards[n + i];
newCards[2 * i + 1] = cards[i];
}
return newCards;
}
// 打印牌序
void printCards(const std::vector<int>& cards) {
for (size_t i = 0; i < cards.size(); ++i) {
if (i > 0) {
std::cout << " ";
}
std::cout << cards[i];
}
std::cout << std::endl;
}
// 判断是否回到初始顺序
bool isSame(const std::vector<int>& cards1, const std::vector<int>& cards2) {
for (size_t i = 0; i < cards1.size(); ++i) {
if (cards1[i] != cards2[i]) {
return false;
}
}
return true;
}
int main() {
int n;
std::cin >> n;
// 初始化初始牌序
std::vector<int> originalCards(2 * n);
for (int i = 0; i < 2 * n
简化
cpp
#include <iostream>
#include <vector>
// 打印牌序
void printCards(const std::vector<int>& cards) {
for (size_t i = 0; i < cards.size(); ++i) {
std::cout << (i > 0 ? " " : "") << cards[i];
}
std::cout << std::endl;
}
int main() {
int n;
std::cin >> n;
// 初始化牌序
std::vector<int> cards(2 * n);
for (int i = 0; i < 2 * n; ++i) {
cards[i] = i + 1;
}
std::vector<int> originalCards = cards;
// 打印初始牌序
printCards(cards);
int m = 0;
do {
std::vector<int> newCards(2 * n);
for (int i = 0; i < n; ++i) {
newCards[2 * i] = cards[n + i];
newCards[2 * i + 1] = cards[i];
}
cards = newCards;
m++;
std::cout << m << ":";
printCards(cards);
} while (cards != originalCards);
std::cout << "m=" << m << std::endl;
return 0;
}
代码解释
- 输入处理:
- 程序开始时,从标准输入读取一个整数
n
,它代表了牌的数量的一半(总共有2 * n
张牌)。
- 程序开始时,从标准输入读取一个整数
- 牌序初始化:
- 创建一个
std::vector<int>
类型的cards
数组,用于存储牌的顺序。通过循环将牌从1
到2 * n
依次放入数组中,同时将这个初始牌序复制给originalCards
,用于后续比较是否恢复到初始状态。
- 创建一个
- 初始牌序输出:
- 调用
printCards
函数打印初始的牌序。该函数会遍历cards
数组并按格式输出。
- 调用
- 洗牌循环:
- 使用
do - while
循环进行洗牌操作,直到牌序恢复到初始状态。 - 在每次循环中,创建一个新的
newCards
数组,按照洗牌规则(即把后n
张牌和前n
张牌交叉排列)更新newCards
的元素。 - 洗牌次数...
- 使用
简化
cpp
#include <iostream>
#include <vector>
// 打印牌序
void printCards(const std::vector<int>& cards) {
for (int card : cards) std::cout << card << " ";
std::cout << std::endl;
}
int main() {
int n;
std::cin >> n;
std::vector<int> cards(2 * n), original(2 * n);
for (int i = 0; i < 2 * n; ++i) {
cards[i] = original[i] = i + 1;
}
printCards(cards);
int m = 0;
do {
std::vector<int> newCards(2 * n);
for (int i = 0; i < n; ++i) {
newCards[2 * i] = cards[n + i];
newCards[2 * i + 1] = cards[i];
}
cards = newCards;
std::cout << ++m << ":";
printCards(cards);
} while (cards != original);
std::cout << "m=" << m << std::endl;
return 0;
}
简化点说明
printCards
函数:使用范围for
循环来遍历cards
向量,减少了代码量,更简洁地实现了牌序的打印。- 变量声明和初始化:在
main
函数中,将cards
和original
向量的声明和初始化合并在一起,代码更紧凑。 do-while
循环:- 直接在循环体中使用
++m
来增加洗牌次数并输出,避免了额外的m++
语句。 - 循环条件使用
cards != original
直接比较向量是否相等,代码更加直观。
- 直接在循环体中使用
代码解释
- 输入处理:从标准输入读取整数
n
,确定牌的数量。 - 牌序初始化:创建
cards
和original
向量,将其初始化为1
到2 * n
的顺序。 - 初始牌序输出:调用
printCards
函数打印初始牌序。 - 洗牌循环:
- 在
do-while
循环中,每次进行洗牌操作,生成新的牌序newCards
。 - 将
newCards
赋值给cards
,更新当前牌序。 - 打印当前洗牌次数和新的牌序。
- 循环条件是
cards
不等于original
,即未恢复到初始顺序。
- 在
- 输出结果:循环结束后,输出总的洗牌次数
m
。
用小学级别的c++写
cpp
#include <iostream>
using namespace std;
// 定义一个函数来打印牌的顺序
void printCards(int cards[], int size) {
for (int i = 0; i < size; i++) {
if (i > 0) {
cout << " ";
}
cout << cards[i];
}
cout << endl;
}
// 定义一个函数来进行一次洗牌操作
void shuffle(int cards[], int n) {
int newCards[20000]; // 假设 n 最大为 10000,所以 2n 最大为 20000
for (int i = 0; i < n; i++) {
newCards[2 * i] = cards[n + i];
newCards[2 * i + 1] = cards[i];
}
for (int i = 0; i < 2 * n; i++) {
cards[i] = newCards[i];
}
}
// 定义一个函数来检查是否回到初始顺序
bool isSame(int cards[], int original[], int size) {
for (int i = 0; i < size; i++) {
if (cards[i] != original[i]) {
return false;
}
}
return true;
}
int main() {
int n;
cin >> n;
int cards[20000];
int original[20000];
// 初始化牌的顺序
for (int i = 0; i < 2 * n; i++) {
cards[i] = i + 1;
original[i] = i + 1;
}
// 打印初始牌序
printCards(cards, 2 * n);
int m = 0;
do {
shuffle(cards, n);
m++;
cout << m << ":";
printCards(cards, 2 * n);
} while (!isSame(cards, original, 2 * n));
cout << "m=" << m << endl;
return 0;
}
代码解释:
-
输入部分:
- 程序开始运行后,会从键盘读取一个整数
n
,它代表了总牌数的一半,也就是有2 * n
张牌。
- 程序开始运行后,会从键盘读取一个整数
-
初始化牌的顺序:
-...
简化
cpp
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
// 初始化牌序,用数组存储 2n 张牌
int cards[20000], original[20000];
for (int i = 0; i < 2 * n; i++) {
cards[i] = original[i] = i + 1;
cout << cards[i];
if (i < 2 * n - 1) {
cout << " ";
}
}
cout << endl;
int m = 0;
do {
int newCards[20000];
// 进行洗牌操作
for (int i = 0; i < n; i++) {
newCards[2 * i] = cards[n + i];
newCards[2 * i + 1] = cards[i];
}
for (int i = 0; i < 2 * n; i++) {
cards[i] = newCards[i];
}
m++;
cout << m << ":";
for (int i = 0; i < 2 * n; i++) {
cout << cards[i];
if (i < 2 * n - 1) {
cout << " ";
}
}
cout << endl;
} while (true);
for (int i = 0; i < 2 * n; i++) {
if (cards[i] != original[i]) {
break;
}
if (i == 2 * n - 1) {
cout << "m=" << m << endl;
return 0;
}
}
}
代码简化说明
- 减少函数使用:去掉了原代码中的
printCards
、shuffle
和isSame
函数,将这些函数的功能直接集成到main
函数中,使代码结构更简单,更适合小学级别的理解。 - 初始化与打印合并:在初始化牌序数组的同时,直接将初始牌序打印出来,减少了额外的循环和代码量。
- 洗牌操作直接实现:在
do - while
循环中直接进行洗牌操作,避免了函数调用的复杂性。 - 顺序检查逻辑内联:将检查是否回到初始顺序的逻辑直接写在
do - while
循环内部,不使用额外的函数。
代码解释
- 输入读取:从标准输入读取一个整数
n
,表示牌的数量的一半(总共2 * n
张牌)。 - 初始化牌序:创建两个数组
cards
和original
来存储当前牌序和初始牌序,并将其初始化为1
到2 * n
的顺序,同时打印初始牌序。 - 洗牌循环:
- 使用
do - while
循环进行洗牌操作。 - 在每次循环中,创建一个新数组
newCards
,按照洗牌规则更新newCards
的元素,然后将newCards
赋值给cards
。 - 打印当前洗牌次数和新的牌序。
- 循环内部有一个检查是否回到初始顺序的逻辑,如果回到初始顺序则输出洗牌次数并结束程序。
- 使用
注意事项
代码中数组大小设定为 20000
是为了适应 n
最大为 10000
的情况(2 * n
最大为 20000
),实际应用中可以根据需求动态调整。同时,代码中使用了固定大小的数组,对于更大的 n
值可能会导致栈溢出,在更复杂的场景中可以考虑使用动态数组(如 std::vector
)。
#include<bits/stdc++.h> using namespace std; int main(){ int n,a[20005],cnt=0; cin>>n; for(int i=1;i<=2*n;i++){ a[i]=i; cout<<a[i]<<" "; } cout<<endl; while(1){ int b[20005],x=2,y=1,flag=0; for(int i=1;i<=n;i++){ b[x]=a[i]; x+=2; } for(int i=1+n;i<=2*n;i++){ b[y]=a[i]; y+=2; } cnt++; cout<<cnt<<":"; for(int i=1;i<=2*n;i++){ cout<<b[i]<<" "; a[i]=b[i]; if(a[i]!=i) flag=1; } cout<<endl; if(flag==0) break; } cout<<"m="<<cnt; }
代码功能概述
这段 C++ 代码实现了对给定的 2n
张牌进行洗牌操作,直到牌序恢复到初始状态,并输出每次洗牌后的牌序以及总的洗牌次数。具体来说,程序从标准输入读取一个整数 n
,然后模拟洗牌过程,每次洗牌后检查牌序是否回到初始状态,若回到初始状态则停止洗牌并输出总的洗牌次数。
代码详细解释
-
头文件和命名空间:
cpp
#include<bits/stdc++.h> using namespace std;
#include<bits/stdc++.h>
:这是一个非标准的头文件,它包含了所有标准库的头文件,方便编写代码时无需逐个包含所需的头文件,但在一些竞赛环境外不建议使用,因为它会增加编译时间且可能导致代码的可移植性问题。using namespace std;
:使用标准命名空间,这样在代码中使用标准库的类和函数时可以省略std::
前缀。
-
主函数和变量定义:
cpp
int main(){ int n,a[20005],cnt=0; cin>>n;
n
:表示输入的整数,代表牌数量的一半(总共有2n
张牌)。a[20005]
:用于存储当前的牌序,数组大小为20005
是为了确保能存储最大可能的牌序(当n
最大为10000
时,2n
最大为20000
)。cnt
:用于记录洗牌的次数,初始化为0
。cin>>n;
:从标准输入读取整数n
。
-
初始化牌序并输出初始状态:
cpp
for(int i=1;i<=2*n;i++){ a[i]=i; cout<<a[i]<<" "; } cout<<endl;
- 通过循环将数组
a
初始化为1
到2n
的顺序,这是初始的牌序。 - 同时将初始牌序输出,每个牌编号之间用空格分隔,最后换行。
- 通过循环将数组
-
洗牌循环:
cpp
while(1){ int b[20005],x=2,y=1,flag=0; for(int i=1;i<=n;i++){ b[x]=a[i]; x+=2; } for(int i=1+n;i<=2*n;i++){ b[y]=a[i]; y+=2; }
while(1)
:这是一个无限循环,用于不断进行洗牌操作,直到满足退出条件。b[20005]
:用于临时存储洗牌后的牌序。x
和y
:分别用于确定b
数组中存储牌编号的位置。- 第一个
for
循环将原牌序a
中前n
张牌依次放入b
数组的偶数位置。 - 第二个
for
循环将原牌序a
中后n
张牌依次放入b
数组的奇数位置。
-
更新牌序、输出洗牌结果并检查是否回到初始状态:
cpp
cnt++; cout<<cnt<<":"; for(int i=1;i<=2*n;i++){ cout<<b[i]<<" "; a[i]=b[i]; if(a[i]!=i) flag=1; } cout<<endl; if(flag==0) break;
cnt++
:洗牌次数加1
。cout<<cnt<<":";
:输出当前的洗牌次数。- 第三个
for
循环将洗牌后的牌序b
输出,同时更新数组a
为新的牌序。 if(a[i]!=i) flag=1;
:检查当前牌序是否与初始牌序相同,如果有任何一张牌的位置不对,则将flag
置为1
。if(flag==0) break;
:如果flag
为0
,说明牌序已经回到初始状态,退出循环。
-
输出总的洗牌次数:
cpp
cout<<"m="<<cnt;
- 输出总的洗牌次数。
代码优化建议
- 头文件:建议使用具体的标准库头文件,如
#include <iostream>
,避免使用#include<bits/stdc++.h>
。 - 数组大小:可以考虑使用动态数组(如
std::vector
)来避免固定大小数组可能带来的空间浪费和越界风险。 - 代码可读性:可以将洗牌操作、检查是否回到初始状态等功能封装成独立的函数,提高代码的可读性和可维护性。
复杂度分析
- 时间复杂度:每次洗牌操作需要遍历
2n
张牌,假设经过m
次洗牌后回到初始状态,则总的时间复杂度为 O(m×n)。 - 空间复杂度:使用了两个大小为
2n
的数组a
和b
来存储牌序,因此空间复杂度为 O(n)。
把这段代码简化
cpp
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int cards[20005];
for (int i = 1; i <= 2 * n; i++) {
cards[i] = i;
cout << i << (i < 2 * n ? " " : "\n");
}
int shuffleCount = 0;
while (true) {
int newCards[20005];
for (int i = 1; i <= n; i++) {
newCards[2 * i] = cards[i];
newCards[2 * i - 1] = cards[n + i];
}
shuffleCount++;
cout << shuffleCount << ":";
bool isOriginal = true;
for (int i = 1; i <= 2 * n; i++) {
cout << newCards[i] << (i < 2 * n ? " " : "\n");
cards[i] = newCards[i];
if (cards[i] != i) isOriginal = false;
}
if (isOriginal) break;
}
cout << "m=" << shuffleCount;
return 0;
}
简化说明
- 减少变量:去掉了不必要的变量
x
、y
和flag
,直接在合适的地方进行逻辑处理,让代码更简洁。 - 合并循环:将原本分开为两个循环给
b
数组赋值的操作,合并到一个循环中,减少代码冗余。 - 简化逻辑判断:将判断是否回到初始顺序的逻辑与输出新牌序的循环结合在一起,通过一个布尔变量
isOriginal
来标记是否回到初始状态。
代码解释
- 输入和初始化:
- 从标准输入读取
n
。 - 初始化
cards
数组为初始牌序,同时输出初始牌序。
- 从标准输入读取
- 洗牌循环:
- 在
while (true)
循环中进行洗牌操作。 - 每次洗牌时,根据规则生成新的牌序存于
newCards
数组。 - 增加洗牌次数
shuffleCount
并输出当前洗牌次数。 - 在输出新牌序的同时检查是否回到初始顺序,如果有一张牌位置不对,
isOriginal
就设为false
。 - 如果
isOriginal
为true
,说明回到初始顺序,跳出循环。
- 在
- 输出结果:输出总的洗牌次数。
#include<bits/stdc++.h> using namespace std; int main(){ int n,a[20005],cnt=0; cin>>n; for(int i=1;i<=2*n;i++){ a[i]=i; cout<<a[i]<<" "; } cout<<endl; while(1){ int b[20005],x=2,y=1,flag=0; for(int i=1;i<=n;i++){ b[x]=a[i]; x+=2; } for(int i=1+n;i<=2*n;i++){ b[y]=a[i]; y+=2; } cnt++; cout<<cnt<<":"; for(int i=1;i<=2*n;i++){ cout<<b[i]<<" "; a[i]=b[i]; if(a[i]!=i) flag=1; } cout<<endl; if(flag==0) break; } cout<<"m="<<cnt; }
以下是对这段代码的简化和优化分析,我们会尽量保持代码逻辑不变,同时减少代码冗余,提高可读性。
简化思路
- 减少不必要的变量:原代码中
x
和y
用于控制新数组b
的索引,可直接通过计算来确定索引,无需额外变量。 - 合并循环:可以将赋值给新数组
b
的两个循环合并为一个,使代码更简洁。 - 优化判断逻辑:将判断是否回到初始状态的逻辑与赋值和输出操作结合,减少代码量。
简化后的代码
cpp
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int cards[20005];
// 初始化并输出初始牌序
for (int i = 1; i <= 2 * n; ++i) {
cards[i] = i;
cout << cards[i];
if (i < 2 * n) cout << " ";
}
cout << endl;
int shuffleCount = 0;
while (true) {
int newCards[20005];
// 进行洗牌操作
for (int i = 1; i <= n; ++i) {
newCards[2 * i - 1] = cards[n + i];
newCards[2 * i] = cards[i];
}
shuffleCount++;
cout << shuffleCount << ":";
bool isOriginal = true;
// 输出新牌序并更新原数组,同时检查是否回到初始状态
for (int i = 1; i <= 2 * n; ++i) {
cout << newCards[i];
if (i < 2 * n) cout << " ";
cards[i] = newCards[i];
if (cards[i] != i) isOriginal = false;
}
cout << endl;
if (isOriginal) break;
}
cout << "m=" << shuffleCount;
return 0;
}
代码解释
-
输入与初始化:
- 从标准输入读取
n
,它表示牌数量的一半。 - 定义数组
cards
用于存储牌的顺序,通过循环将其初始化为1
到2 * n
的顺序,并输出初始牌序。
- 从标准输入读取
-
洗牌循环:
- 使用
while (true)
构建一个无限循环,在每次循环中进行洗牌操作。 - 定义
newCards
数组用于存储洗牌后的牌序。 - 通过一个循环完成洗牌操作,将后
n
张牌和前n
张牌交叉放入newCards
数组。 - 增加洗牌次数
shuffleCount
并输出当前洗牌次数。
- 使用
-
检查与更新:
- 遍历
newCards
数组,输出新的牌序,同时将newCards
的值赋给cards
。 - 在遍历过程中,检查是否回到初始状态,如果有任何一张牌的位置不对,将
isOriginal
标记为false
。 - 如果
isOriginal
为true
,说明回到了初始状态,使用break
跳出循环。
- 遍历
-
输出结果:
- 循环结束后,输出总的洗牌次数。
复杂度分析
- 时间复杂度:每次洗牌和检查是否回到初始状态都需要遍历
2 * n
个元素,假设经过m
次洗牌回到初始状态,时间复杂度为 O(m∗n)。 - 空间复杂度:使用了两个大小为
2 * n
的数组cards
和newCards
,空间复杂度为 O(n)。
只用20行代码内
cpp
#include <iostream>
using namespace std;
int main() {
int n, a[20005], cnt = 0;
cin >> n;
for (int i = 1; i <= 2 * n; i++) a[i] = i, cout << a[i] << (i < 2 * n ? " " : "\n");
while (1) {
int b[20005];
for (int i = 1; i <= n; i++) b[2 * i - 1] = a[n + i], b[2 * i] = a[i];
cnt++;
cout << cnt << ":";
bool flag = true;
for (int i = 1; i <= 2 * n; i++) cout << b[i] << (i < 2 * n ? " " : "\n"), a[i] = b[i], flag &= a[i] == i;
if (flag) break;
}
cout << "m=" << cnt;
return 0;
}
代码解释:
- 输入与初始牌序输出:
- 读取
n
后,使用一个for
循环初始化数组a
为初始牌序,同时将初始牌序输出,每个元素间用空格分隔,最后换行。
- 读取
- 洗牌循环:
- 在
while (1)
无限循环中进行洗牌操作。 - 每次循环创建数组
b
存储洗牌后的牌序,通过一个for
循环完成洗牌规则。 - 增加洗牌次数
cnt
并输出当前洗牌次数。
- 在
- 检查与更新:
- 另一个
for
循环输出新牌序,更新a
数组,同时使用逻辑与&=
操作符检查是否回到初始状态。 - 如果
flag
为true
,说明回到初始状态,跳出循环。
- 另一个
- 输出结果:
- 循环结束后输出总的洗牌次数。
简化
cpp
#include <iostream>
int main() {
int n, cards[20000];
std::cin >> n;
for (int i = 1; i <= 2 * n; ++i) {
cards[i] = i;
std::cout << i << (i < 2 * n ? " " : "\n");
}
int times = 0;
while (true) {
int newCards[20000];
for (int i = 1; i <= n; ++i) {
newCards[2 * i - 1] = cards[n + i];
newCards[2 * i] = cards[i];
}
std::cout << ++times << ":";
bool isOriginal = true;
for (int i = 1; i <= 2 * n; ++i) {
std::cout << newCards[i] << (i < 2 * n ? " " : "\n");
cards[i] = newCards[i];
if (cards[i] != i) isOriginal = false;
}
if (isOriginal) break;
}
std::cout << "m=" << times;
return 0;
}
简化点说明
- 命名空间:使用
std::
限定符而不是using namespace std;
,避免命名冲突,虽然代码量稍增,但更规范。 - 变量命名:把
cnt
改为times
,更具可读性,让人一眼就知道这是记录洗牌次数的变量;a
数组改为cards
,b
数组改为newCards
,能清晰体现数组用途。 - 代码逻辑:
- 减少不必要的变量,像原代码里用于控制数组索引的
x
和y
就去掉了,直接通过计算得到索引。 - 把赋值给新数组的两个循环合并成一个,使代码更简洁。
- 将判断是否回到初始状态的逻辑与输出新牌序的循环结合,减少代码重复。
- 减少不必要的变量,像原代码里用于控制数组索引的
- 输出格式:在输出元素时,通过
i < 2 * n ? " " : "\n"
这种简洁的方式控制空格和换行,让代码更紧凑。
代码解释
- 输入与初始化:
- 从标准输入读取
n
,表示牌数量的一半。 - 用
for
循环将cards
数组初始化为1
到2 * n
的顺序,同时输出初始牌序。
- 从标准输入读取
- 洗牌循环:
while (true)
构成无限循环,在每次循环中进行洗牌操作。- 创建
newCards
数组存储洗牌后的牌序,通过for
循环按洗牌规则填充。 - 增加
times
计数并输出当前洗牌次数。
- 检查与更新:
- 另一个
for
循环输出新牌序,更新cards
数组,同时检查是否回到初始状态。若有牌位置不对,isOriginal
设为false
。 - 若
isOriginal
为true
,说明回到初始状态,跳出循环。
- 另一个
- 输出结果:循环结束后输出总的洗牌次数。
只用10行代码实现
cpp
#include <iostream>
int main() {
int n, a[20000], m = 0; std::cin >> n;
for (int i = 1; i <= 2 * n; ++i) a[i] = i, std::cout << i << (i < 2 * n ? " " : "\n");
while (true) {
int b[20000]; for (int i = 1; i <= n; ++i) b[2 * i - 1] = a[n + i], b[2 * i] = a[i];
std::cout << ++m << ":"; bool same = true;
for (int i = 1; i <= 2 * n; ++i) std::cout << b[i] << (i < 2 * n ? " " : "\n"), a[i] = b[i], same &= a[i] == i;
if (same) break;
}
std::cout << "m=" << m;
}
代码解释:
-
头文件和主函数声明:
cpp
#include <iostream> int main() {
包含标准输入输出流的头文件,并开始主函数。
-
变量定义、输入和初始牌序输出:
cpp
int n, a[20000], m = 0; std::cin >> n; for (int i = 1; i <= 2 * n; ++i) a[i] = i, std::cout << i << (i < 2 * n ? " " : "\n");
- 定义了变量
n
用于接收输入的牌数量相关参数,a
数组用于存储牌的顺序,m
用于记录洗牌次数并初始化为 0。然后读取输入的n
。 - 通过
for
循环初始化a
数组为初始牌序,同时输出初始牌序,每个元素之间用空格分隔,最后一个元素后换行。
- 定义了变量
-
洗牌循环:
cpp
while (true) { int b[20000]; for (int i = 1; i <= n; ++i) b[2 * i - 1] = a[n + i], b[2 * i] = a[i];
- 使用
while (true)
构建一个无限循环进行洗牌操作。 - 定义临时数组
b
用于存储洗牌后的牌序,通过for
循环根据洗牌规则填充b
数组。
- 使用
-
输出洗牌次数、新牌序并检查是否回到初始状态:
cpp
std::cout << ++m << ":"; bool same = true; for (int i = 1; i <= 2 * n; ++i) std::cout << b[i] << (i < 2 * n ? " " : "\n"), a[i] = b[i], same &= a[i] == i;
- 输出当前的洗牌次数。
- 定义布尔变量
same
用于标记是否回到初始状态,初始化为true
。 - 通过
for
循环输出新的牌序,更新a
数组,同时检查每个位置的牌是否和初始位置相同,若有不同则same
变为false
。
-
结束循环和输出总洗牌次数:
cpp
if (same) break; } std::cout << "m=" << m;
- 如果
same
为true
,说明回到了初始状态,使用break
跳出循环。 - 循环结束后,输出总的洗牌次数。
- 如果
注意事项:
- 这种将多行逻辑合并在一行的方式虽然减少了代码行数,但会在一定程度上降低代码的可读性,在实际开发中要谨慎使用。
- 数组大小
20000
是为了适应题目中n
小于 10000 的情况(2 * n
最大为 20000),可以根据实际情况调整。
把这段话换成最简便的
cpp
#include <iostream>
int main() {
int n, a[20000]{}, m = 0; std::cin >> n;
for (int i = 1; i <= 2 * n; std::cout << i << (++i <= 2 * n ? " " : "\n")) a[i] = i;
while (1) {
int b[20000]{}; for (int i = 1; i <= n; ++i) b[2 * i - 1] = a[n + i], b[2 * i] = a[i];
std::cout << ++m << ":"; bool s = 1;
for (int i = 1; i <= 2 * n; std::cout << b[i] << (++i <= 2 * n ? " " : "\n")) a[i] = b[i], s &= a[i] == i;
if (s) break;
}
std::cout << "m=" << m;
}
进一步简化说明
- 数组初始化:使用花括号
{}
对数组a
和b
进行初始化,在 C++ 里这是一种简洁的默认初始化方式。 for
循环简化:在两个for
循环的条件判断和迭代部分做了简化,把i
的自增操作与输出逻辑合并在一起,减少了代码量。- 布尔变量缩写:把
same
变量缩写成s
,进一步压缩代码长度。 while
条件简化:将while (true)
简化为while (1)
,虽然两者作用相同,但while (1)
更简洁。
代码解释
整体逻辑和之前的 10 行代码版本一致,只是通过上述简化操作让代码变得更加简短:
- 输入
n
后,初始化a
数组为初始牌序并输出。 - 进入无限循环进行洗牌操作,每次洗牌后把结果存到
b
数组。 - 输出当前洗牌次数,接着输出新牌序,同时更新
a
数组,判断是否回到初始状态。 - 若回到初始状态,跳出循环并输出总的洗牌次数。
注意事项
- 这种极致的简化会极大降低代码的可读性,不利于代码的维护和理解,仅适用于对代码行数有严格要求的特殊场景,比如代码竞赛中的代码压缩挑战。
- 数组大小
20000
是为了适配n
小于 10000 的情况(2 * n
最大为 20000),实际使用时可按需调整。
#include<iostream> using namespace std; int main(){ int n,a[20005],cnt=0; cin>>n; for(int i=1;i<=2*n;i++) a[i]=i,cout<<a[i]<<(i<2*n?" ":"\n"); while(1){ int b[20005]; for(int i=1;i<=n;i++) b[2*i-1]=a[n+i],b[2*i]=a[i]; cnt++; cout<<cnt<<":"; bool flag=true; for(int i=1;i<=2*n;i++) cout<<b[i]<<(i<2*n?" ":"\n"),a[i]=b[i],flag&=a[i]==i; if(flag) break; } cout<<"m="<<cnt; return 0; } 把这段话换成最简便的
cpp
#include <iostream>
int main() {
int n, a[20005], m = 0; std::cin >> n;
for (int i = 1; i <= 2 * n; std::cout << i << (++i <= 2 * n ? " " : "\n")) a[i] = i;
for (;!([&]() {
int b[20005]; for (int i = 1; i <= n; ++i) b[2 * i - 1] = a[n + i], b[2 * i] = a[i];
std::cout << ++m << ":"; bool s = 1;
for (int i = 1; i <= 2 * n; std::cout << b[i] << (++i <= 2 * n ? " " : "\n")) a[i] = b[i], s &= a[i] == i;
return s;
})(););
std::cout << "m=" << m;
}
简化思路及解释
1. 变量和输入部分
cpp
int n, a[20005], m = 0; std::cin >> n;
- 直接在一行内完成变量
n
(用于接收输入的数值)、数组a
(存储牌的顺序)和计数器m
(记录洗牌次数)的定义,同时读取输入,减少代码行数。
2. 初始牌序输出和数组初始化
cpp
for (int i = 1; i <= 2 * n; std::cout << i << (++i <= 2 * n ? " " : "\n")) a[i] = i;
- 将初始化数组
a
和输出初始牌序的操作合并到一个for
循环中。在循环的条件和迭代部分巧妙利用++i
来控制元素的输出格式,即元素间用空格分隔,最后一个元素后换行。
3. 洗牌循环部分
cpp
for (;!([&]() {
int b[20005]; for (int i = 1; i <= n; ++i) b[2 * i - 1] = a[n + i], b[2 * i] = a[i];
std::cout << ++m << ":"; bool s = 1;
for (int i = 1; i <= 2 * n; std::cout << b[i] << (++i <= 2 * n ? " " : "\n")) a[i] = b[i], s &= a[i] == i;
return s;
})(););
- 使用一个无初始化、无迭代部分的
for
循环,循环条件是一个 lambda 表达式的返回值取反。 - lambda 表达式
[&]()
表示按引用捕获外部变量,在其内部完成洗牌操作:- 创建临时数组
b
存储洗牌后的牌序。 - 输出当前洗牌次数
m
并自增。 - 遍历
b
数组输出新牌序,同时更新a
数组,并判断是否回到初始顺序,结果存储在布尔变量s
中。 - 最后返回
s
的值。
- 创建临时数组
- 只要
s
为false
(即未回到初始顺序),循环就会继续。
4. 输出结果
cpp
std::cout << "m=" << m;
- 当牌序回到初始状态,循环结束,输出总的洗牌次数。
注意事项
- 这种简化方式虽然极大地减少了代码行数,但代码的可读性和可维护性大幅降低。lambda 表达式和复杂的
for
循环结构可能会让代码难以理解,不适合在常规开发中使用,仅适用于对代码长度有严格要求的特殊场景,如代码竞赛。 - 数组大小
20005
是为了适应n
小于 10000 的情况(2 * n
最大为 20000),可根据实际需求调整。
true在编程里的意思
在编程中,true
通常是一个布尔类型的值,下面为你详细介绍其在不同编程语言中的含义和使用方式:
布尔类型基础概念
布尔类型(Boolean)是一种基本的数据类型,它只有两个可能的值:true
和 false
,主要用于逻辑判断和条件控制。在程序里,很多操作和语句需要根据某个条件的真假来决定执行的流程,true
就代表条件成立、满足或者为真的情况。
不同编程语言中 true
的使用
1. C++
在 C++ 里,true
是布尔类型 bool
的一个字面量。布尔类型通常用于逻辑表达式和条件判断语句。
cpp
#include <iostream>
int main() {
bool isTrue = true;
if (isTrue) {
std::cout << "The condition is true." << std::endl;
}
return 0;
}
在上述代码中,isTrue
变量被赋值为 true
,if
语句判断 isTrue
的值为真,所以会执行其内部的输出语句。
2. Java
Java 同样有布尔类型 boolean
,true
是该类型的一个合法值,常用于条件判断和循环控制。
java
public class Main {
public static void main(String[] args) {
boolean condition = true;
if (condition) {
System.out.println("The condition is true.");
}
}
}
这里 condition
变量的值为 true
,if
语句会因为条件为真而执行相应的输出操作。
3. Python
Python 中布尔类型是 bool
,True
(注意首字母大写)是布尔类型的真值,常被用于逻辑判断。
python
condition = True
if condition:
print("The condition is true.")
在这个 Python 代码片段中,condition
被赋值为 True
,if
语句会基于此执行后续的打印操作。
4. JavaScript
JavaScript 也支持布尔类型,true
是布尔值之一,广泛应用于逻辑判断和流程控制。
javascript
let isTrue = true;
if (isTrue) {
console.log("The condition is true.");
}
上述 JavaScript 代码中,isTrue
变量的值为 true
,if
语句的条件满足,会执行内部的 console.log
语句。
与 true
相关的逻辑运算
true
经常参与逻辑运算,如逻辑与(&&
)、逻辑或(||
)和逻辑非(!
),以下是简单示例:
逻辑与(&&
)
只有当两个操作数都为 true
时,结果才为 true
。
cpp
// C++ 示例
bool a = true;
bool b = true;
bool result = a && b; // result 为 true
逻辑或(||
)
只要两个操作数中有一个为 true
,结果就为 true
。
python
# Python 示例
a = True
b = False
result = a or b # result 为 True
逻辑非(!
)
对操作数取反,true
取反后为 false
。
java
// Java 示例
boolean a = true;
boolean result = !a; // result 为 false
题目描述 在冰壶比赛中,给出一个目标点P以及一个规定的正整数r。每一局由甲和乙两队轮流投冰壶各8次后,该局比赛结束。此时,哪一方的冰壶最终离目标点P更近,该方得分,另一方不得分。得分方每颗离目标点P距离小于或等于r、位置较另一队所有冰壶都更接近目标点P的冰壶都可以得1分 比赛最多进行10局。双方之间的某局比赛结束后,落后一方可以弃权。此时,比赛不再进行下去 已知每一局结束时,双方的每个冰壶离目标点P的距离以及正整数r,请写一个程序判断两队之间每一局比赛的得分,以及总得分 输入描述 第一行一个正整数r 以下有若干行(不超过20行),每一行8个正整数(之间用一个空格间隔) 第二行的第j个数表示第一局比赛结束时,甲方的第j个冰壶距离目标点P的距离 第三行的第j个数表示第一局比赛结束时,乙方的第j个冰壶距离目标点P的距离 …… 第2k行的第j个数表示第k局比赛结束时,甲方的第j个冰壶距离目标点P的距离 第2k+1行的第j个数表示第k局比赛结束时,乙方的第j个冰壶距离目标点P的距离 如果有一方中途弃权,则最后一行(偶数行)只有一个整数-1,表示此时发生弃权情况 输出描述 输出若干行,每行两个整数,中间以一个冒号间隔,表示每一局比赛甲乙双方的比分(甲得分在前)。最后一行有2个整数,中间以一个冒号间隔,表示甲乙双方比赛的最终得分(甲得分在前) 样例 输入 12 5 60 25 74 71 100 3 93 66 75 70 66 52 73 67 14 93 84 74 99 79 64 89 22 65 5 95 59 80 8 35 61 65 61 49 60 58 50 32 85 68 38 96 38 82 64 26 93 74 92 47 21 97 30 45 78 44 99 90 27 3 46 55 34 49 45 83 3 18 1 67 23 60 47 95 81 17 1 87 85 18 74 74 84 29 20 27 71 37 60 26 56 23 65 67 49 57 7 62 92 52 5 10 69 46 97 88 28 76 27 66 7 89 89 94 31 11 20 1 17 19 48 35 6 77 61 45 21 52 11 76 70 73 99 85 55 90 25 20 7 64 24 94 4 3 43 32 74 10 93 35 77 77 100 63 91 10 73 22 57 输出 2:0 0:2 0:0 0:1 0:0 0:0 1:0 1:0 0:2 1:0 5:5
以下是实现该功能的 Python 代码:
python
# 读取正整数 r
r = int(input())
# 初始化甲乙双方的总得分
total_score_a = 0
total_score_b = 0
# 用于存储每一局的比分
scores_per_round = []
while True:
try:
# 读取甲方这一局每个冰壶距离目标点 P 的距离
distances_a = list(map(int, input().split()))
if len(distances_a) == 1 and distances_a[0] == -1:
break
# 读取乙方这一局每个冰壶距离目标点 P 的距离
distances_b = list(map(int, input().split()))
# 找出乙方冰壶的最小距离
min_distance_b = min(distances_b)
# 找出甲方冰壶的最小距离
min_distance_a = min(distances_a)
# 初始化这一局甲乙双方的得分
score_a = 0
score_b = 0
if min_distance_a < min_distance_b:
# 甲方得分情况
for distance in distances_a:
if distance <= r and distance < min_distance_b:
score_a += 1
elif min_distance_b < min_distance_a:
# 乙方得分情况
for distance in distances_b:
if distance <= r and distance < min_distance_a:
score_b += 1
c++
cpp
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
int r;
std::cin >> r;
int total_score_a = 0;
int total_score_b = 0;
std::vector<std::pair<int, int>> scores_per_round;
while (true) {
std::vector<int> distances_a(8);
for (int i = 0; i < 8; ++i) {
std::cin >> distances_a[i];
}
if (distances_a[0] == -1) {
break;
}
std::vector<int> distances_b(8);
for (int i = 0; i < 8; ++i) {
std::cin >> distances_b[i];
}
int min_distance_b = *std::min_element(distances_b.begin(), distances_b.end());
int min_distance_a = *std::min_element(distances_a.begin(), distances_a.end());
int score_a = 0;
int score_b = 0;
if (min_distance_a < min_distance_b) {
for (int distance : distances_a) {
if (distance <= r && distance < min_distance_b) {
score_a++;
}
}
} else if (min_distance_b < min_distance_a) {
for (int distance : distances_b) {
if (distance <= r && distance < min_distance_a) {
score_b++;
}
}
}
scores_per_round.emplace_back(score_a, score_b);
total_score_a += score_a;
total_score_b += score_b;
}
for (const auto& score : scores_per_round) {
std::cout << score.first << ":" << score.second << std::endl;
}
std::cout << total_score_a << ":" << total_score_b << std::endl;
return 0;
}
代码解释:
-
输入读取:
- 首先读取正整数
r
,它是规定的得分距离限制。 - 然后进入一个无限循环,每次循环读取甲方和乙方在一局中每个冰壶距离目标点
P
的距离,存储在distances_a
和distances_b
向量中。 - 如果读取到的甲方第一个距离为
-1
,则表示有一方弃权,跳出循环。
- 首先读取正整数
-
计算每局得分:
- 使用
std::min_element
函数找出乙方和甲方冰壶的最小距离min_distance_b
和min_distance_a
。 - 如果甲方最小距离小于乙方,遍历甲方的冰壶距离,若距离小于等于
r
且小于乙方最小距离,则甲方该冰壶得分,score_a
加 1。 - 反之,如果乙方最小距离小于甲方,遍历乙方的冰壶距离,若满足条件则乙方该冰壶得分,
score_b
加 1。
- 使用
-
存储和更新总分:
- 将每局的得分
score_a
和score_b
作为一个std::pair
存储在scores_per_round
向量中。 - 同时更新甲乙双方的总得分
total_score_a
和total_score_b
。
- 将每局的得分
-
输出结果:
- 遍历
scores_per_round
向量,输出每一局甲乙双方的比分。 - 最后输出甲乙双方比赛的最终得分。
- 遍历
复杂度分析:
- 时间复杂度:对于每一局,找出最小距离的时间复杂度为 O(8),遍历冰壶距离计算得分的时间复杂度也为 O(8),假设最多进行 10 局比赛,总的时间复杂度为 O(10×8)。
- 空间复杂度:主要使用了存储每局比分的向量和每局冰壶距离的向量,空间复杂度为 O(10+8×2)。
int 类型
1. int
类型概述
在 C++ 里,int
是一种基本的数据类型,用于表示整数。它在内存中占据一定的字节数,具体字节数会因编译器和操作系统的不同而有所差异,但通常为 4 个字节。这意味着 int
类型能够表示的整数范围大致是 −231 到 231−1(即 -2147483648 到 2147483647)。
2. 在冰壶比赛代码中 int
类型的使用
2.1 变量定义
cpp
int r;
int total_score_a = 0;
int total_score_b = 0;
r
:用于存储输入的正整数r
,这个r
是冰壶比赛中规定的得分距离限制,即冰壶离目标点P
的距离小于或等于r
才有可能得分。total_score_a
和total_score_b
:分别用于记录甲方和乙方的总得分,初始值都设为 0。
2.2 数组元素类型
cpp
std::vector<int> distances_a(8);
std::vector<int> distances_b(8);
这里使用 std::vector<int>
定义了两个向量 distances_a
和 distances_b
,其中 int
表示向量中的元素类型为整数。这两个向量分别用来存储甲方和乙方在每一局中每个冰壶距离目标点 P
的距离。
2.3 循环计数器
cpp
for (int i = 0; i < 8; ++i) {
std::cin >> distances_a[i];
}
在这个 for
循环里,int i
作为循环计数器,从 0 开始,每次递增 1,直到 i
达到 8 时停止循环。通过这个计数器,我们可以依次读取甲方 8 个冰壶的距离并存储到 distances_a
向量中。
2.4 得分计算
cpp
int score_a = 0;
int score_b = 0;
score_a
和 score_b
分别用于记录每一局甲方和乙方的得分,同样使用 int
类型,初始值设为 0。在后续的得分计算过程中,根据冰壶的距离情况对这两个变量进行累加。
3. int
类型的优点和注意事项
3.1 优点
- 简单高效:
int
是基本数据类型,操作简单,计算机处理速度快,适合用于表示整数类型的数值,如得分、距离等。...
题目描述 在冰壶比赛中,给出一个目标点P以及一个规定的正整数r。每一局由甲和乙两队轮流投冰壶各8次后,该局比赛结束。此时,哪一方的冰壶最终离目标点P更近,该方得分,另一方不得分。得分方每颗离目标点P距离小于或等于r、位置较另一队所有冰壶都更接近目标点P的冰壶都可以得1分 比赛最多进行10局。双方之间的某局比赛结束后,落后一方可以弃权。此时,比赛不再进行下去 已知每一局结束时,双方的每个冰壶离目标点P的距离以及正整数r,请写一个程序判断两队之间每一局比赛的得分,以及总得分 输入描述 第一行一个正整数r 以下有若干行(不超过20行),每一行8个正整数(之间用一个空格间隔) 第二行的第j个数表示第一局比赛结束时,甲方的第j个冰壶距离目标点P的距离 第三行的第j个数表示第一局比赛结束时,乙方的第j个冰壶距离目标点P的距离 …… 第2k行的第j个数表示第k局比赛结束时,甲方的第j个冰壶距离目标点P的距离 第2k+1行的第j个数表示第k局比赛结束时,乙方的第j个冰壶距离目标点P的距离 如果有一方中途弃权,则最后一行(偶数行)只有一个整数-1,表示此时发生弃权情况 输出描述 输出若干行,每行两个整数,中间以一个冒号间隔,表示每一局比赛甲乙双方的比分(甲得分在前)。最后一行有2个整数,中间以一个冒号间隔,表示甲乙双方比赛的最终得分(甲得分在前) 样例 输入 12 5 60 25 74 71 100 3 93 66 75 70 66 52 73 67 14 93 84 74 99 79 64 89 22 65 5 95 59 80 8 35 61 65 61 49 60 58 50 32 85 68 38 96 38 82 64 26 93 74 92 47 21 97 30 45 78 44 99 90 27 3 46 55 34 49 45 83 3 18 1 67 23 60 47 95 81 17 1 87 85 18 74 74 84 29 20 27 71 37 60 26 56 23 65 67 49 57 7 62 92 52 5 10 69 46 97 88 28 76 27 66 7 89 89 94 31 11 20 1 17 19 48 35 6 77 61 45 21 52 11 76 70 73 99 85 55 90 25 20 7 64 24 94 4 3 43 32 74 10 93 35 77 77 100 63 91 10 73 22 57 输出 2:0 0:2 0:0 0:1 0:0 0:0 1:0 1:0 0:2 1:0 5:5
以下是使用 C++ 实现该功能的代码:
cpp
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
int r;
std::cin >> r;
int totalScoreA = 0;
int totalScoreB = 0;
int round = 0;
while (round < 10) {
std::vector<int> distancesA(8);
std::vector<int> distancesB(8);
// 读取甲方每局 8 个冰壶距离
for (int i = 0; i < 8; ++i) {
std::cin >> distancesA[i];
}
// 检查是否弃权
if (distancesA[0] == -1) {
break;
}
// 读取乙方每局 8 个冰壶距离
for (int i = 0; i < 8; ++i) {
std::cin >> distancesB[i];
}
int minDistanceA = *std::min_element(distancesA.begin(), distancesA.end());
int minDistanceB = *std::min_element(distancesB.begin(), distancesB.end());
int scoreA = 0;
int scoreB = 0;
if (minDistanceA < minDistanceB) {
for (int distance : distancesA) {
if (distance <= r && distance < minDistanceB) {
scoreA++;
}
}
} else if (minDistanceB < minDistanceA) {
for (int distance : distancesB) {
if (distance <= r && distance < minDistanceA) {
scoreB++;
}
}
}
std::cout << scoreA << ":" << scoreB << std::endl;
totalScoreA += scoreA;
totalScoreB += scoreB;
round++;
}
std::cout << totalScoreA << ":" << totalScoreB << std::endl;
return 0;
}
代码解释:
-
输入处理:
- 首先读取规定的正整数
r
,它是判断冰壶是否得分的距离限制。 - 在循环中,每次读取甲方和乙方每一局 8 个冰壶距离目标点
P
的距离,分别存储在distancesA
和distancesB
向量中。 - 如果读取甲方距离时第一个值为
-1
,表示有一方弃权,结束比赛。
- 首先读取规定的正整数
-
得分计算:
- 使用
std::min_element
函数分别找出甲方和乙方冰壶距离的最小值minDistanceA
和minDistanceB
。 - 比较两个最小值,如果
minDistanceA < minDistanceB
,遍历甲方的冰壶距离,若距离小于等于r
且小于minDistanceB
,则甲方该冰壶得分,scoreA
加 1;反之,若minDistanceB < minDistanceA
,对乙方进行类似操作。
- 使用
-
输出结果:
- 每局比赛结束后,输出该局甲乙双方的比分,格式为
scoreA:scoreB
。 - 同时更新甲乙双方的总得分
totalScoreA
和totalScoreB
。 - 比赛结束后,输出双方的最终总得分,格式同样为
totalScoreA:totalScoreB
。
- 每局比赛结束后,输出该局甲乙双方的比分,格式为
复杂度分析:
- 时间复杂度:对于每一局比赛,计算最小值的时间复杂度为 O(8),遍历冰壶距离计算得分的时间复杂度也为 O(8),最多进行 10 局比赛,所以总的时间复杂度为 O(10×8)。
- 空间复杂度:主要使用了两个存储 8 个元素的向量和一些整数变量,空间复杂度为 O(8×2)。
加int类型
以下是添加了更多 int
类型变量详细使用说明且对代码结构进行了适当优化的 C++ 代码,用于解决冰壶比赛得分计算问题:
cpp
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
// 存储规定的正整数 r,用于判断冰壶是否在得分范围内
int r;
std::cin >> r;
// 存储甲方和乙方的总得分,初始化为 0
int totalScoreA = 0;
int totalScoreB = 0;
// 记录当前比赛进行的局数,初始化为 0
int round = 0;
// 比赛最多进行 10 局
while (round < 10) {
// 存储甲方每局 8 个冰壶距离目标点 P 的距离
std::vector<int> distancesA(8);
// 存储乙方每局 8 个冰壶距离目标点 P 的距离
std::vector<int> distancesB(8);
// 读取甲方每局 8 个冰壶距离
for (int i = 0; i < 8; ++i) {
std::cin >> distancesA[i];
}
// 检查是否有一方弃权,若甲方第一个输入为 -1 则表示弃权
if (distancesA[0] == -1) {
break;
}
// 读取乙方每局 8 个冰壶距离
for (int i = 0; i < 8; ++i) {
std::cin >> distancesB[i];
}
// 找出甲方 8 个冰壶中距离目标点 P 的最小距离
int minDistanceA = *std::min_element(distancesA.begin(), distancesA.end());
// 找出乙方 8 个冰壶中距离目标点 P 的最小距离
int minDistanceB = *std::min_element(distancesB.begin(), distancesB.end());
// 存储甲方本局的得分,初始化为 0
int scoreA = 0;
// 存储乙方本局的得分,初始化为 0
int scoreB = 0;
// 判断哪一方冰壶离目标点 P 更近,进而计算得分
if (minDistanceA < minDistanceB) {
// 遍历甲方每个冰壶的距离
for (int distance : distancesA) {
// 若该冰壶距离小于等于 r 且小于乙方最小距离,则甲方此冰壶得分
if (distance <= r && distance < minDistanceB) {
scoreA++;
}
}
} else if (minDistanceB < minDistanceA) {
// 遍历乙方每个冰壶的距离
for (int distance : distancesB) {
// 若该冰壶距离小于等于 r 且小于甲方最小距离,则乙方此冰壶得分
if (distance <= r && distance < minDistanceA) {
scoreB++;
}
}
}
// 输出本局甲乙双方的比分
std::cout << scoreA << ":" << scoreB << std::endl;
// 更新甲方的总得分
totalScoreA += scoreA;
// 更新乙方的总得分
totalScoreB += scoreB;
// 局数加 1
round++;
}
// 输出甲乙双方比赛的最终总得分
std::cout << totalScoreA << ":" << totalScoreB << std::endl;
return 0;
}
代码解释
变量定义
int r;
:用于存储从输入中读取的规定正整数r
,它是判断冰壶是否能够得分的距离阈值。int totalScoreA = 0;
和int totalScoreB = 0;
:分别用于记录甲方和乙方在整个比赛过程中的总得分,初始值都设为 0。int round = 0;
:用于记录当前比赛进行到了第几局,初始值为 0。
局内数据处理
std::vector<int> distancesA(8);
和std::vector<int> distancesB(8);
:分别存储甲方和乙方在每一局中 8 个冰壶距离目标点P
的距离,这里的int
类型确保每个距离值都是整数。int minDistanceA
和int minDistanceB
:分别存储甲方和乙方 8 个冰壶中距离目标点P
的最小距离,通过std::min_element
函数计算得出。int scoreA = 0;
和int scoreB = 0;
:分别存储甲方和乙方在每一局中的得分,初始值为 0,根据冰壶距离情况进行累加。
流程控制
for (int i = 0; i < 8; ++i)
:在读取甲方和乙方每局冰壶距离时,使用int
类型的i
作为循环计数器,确保准确读取 8 个距离值。while (round < 10)
:使用int
类型的round
控制比赛局数,最多进行 10 局。
复杂度分析
- 时间复杂度:对于每一局比赛,找出最小距离的操作时间复杂度为 O(8),遍历冰壶距离计算得分的操作时间复杂度也为 O(8),最多进行 10 局比赛,所以总的时间复杂度为 O(10×8)。
- 空间复杂度:主要使用了两个长度为 8 的向量存储冰壶距离,以及几个
int
类型的变量,空间复杂度为 O(8×2)。
简化
cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int r, totalA = 0, totalB = 0;
cin >> r;
for (int round = 0; round < 10; ++round) {
vector<int> a(8), b(8);
for (int i = 0; i < 8; ++i) cin >> a[i];
if (a[0] == -1) break;
for (int i = 0; i < 8; ++i) cin >> b[i];
int minA = *min_element(a.begin(), a.end());
int minB = *min_element(b.begin(), b.end());
int scoreA = 0, scoreB = 0;
if (minA < minB)
for (int d : a) if (d <= r && d < minB) scoreA++;
else if (minB < minA)
for (int d : b) if (d <= r && d < minA) scoreB++;
cout << scoreA << ":" << scoreB << endl;
totalA += scoreA;
totalB += scoreB;
}
cout << totalA << ":" << totalB << endl;
return 0;
}
简化说明
- 命名空间使用:使用
using namespace std;
避免每次使用标准库组件时都写std::
,使代码更简洁。 - 变量命名简化:将
totalScoreA
简化为totalA
,totalScoreB
简化为totalB
,distancesA
简化为a
,distancesB
简化为b
,减少代码长度。 - 循环结构:使用
for
循环替代while
循环控制比赛局数,代码结构更紧凑。 - 输入输出简化:合并了部分输入输出代码,减少冗余。
代码解释
- 输入读取:读取规定的距离
r
,后续每局读取甲方和乙方各 8 个冰壶距离,若甲方第一个输入为-1
则停止比赛。 - 得分计算:找出双方冰壶最小距离,若甲方最小距离小,则遍历甲方冰壶距离计算得分;反之遍历乙方冰壶距离计算得分。
- 结果输出:每局输出该局比分,最后输出总比分。
20行代码内输出
cpp
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
int r, totalA = 0, totalB = 0;
std::cin >> r;
for (int i = 0; i < 10; ++i) {
std::vector<int> a(8), b(8);
for (int j = 0; j < 8; ++j) std::cin >> a[j];
if (a[0] == -1) break;
for (int j = 0; j < 8; ++j) std::cin >> b[j];
int minA = *std::min_element(a.begin(), a.end());
int minB = *std::min_element(b.begin(), b.end());
int scoreA = 0, scoreB = 0;
if (minA < minB) for (int d : a) if (d <= r && d < minB) ++scoreA;
else if (minB < minA) for (int d : b) if (d <= r && d < minA) ++scoreB;
std::cout << scoreA << ":" << scoreB << std::endl;
totalA += scoreA; totalB += scoreB;
}
std::cout << totalA << ":" << totalB << std::endl;
return 0;
}
代码解释:
- 头文件与主函数:
#include <iostream>
:用于输入输出操作。#include <vector>
:用于使用std::vector
容器存储冰壶距离。#include <algorithm>
:使用std::min_element
函数找出最小距离。int main()
:程序的入口函数。
- 变量定义与输入:
int r, totalA = 0, totalB = 0;
:r
为规定的正整数,totalA
和totalB
分别记录甲乙双方总得分,初始化为 0。std::cin >> r;
:读取输入的r
。
- 比赛局数循环:
for (int i = 0; i < 10; ++i)
:最多进行 10 局比赛。
- 每局数据处理:
std::vector<int> a(8), b(8);
:分别存储甲乙双方每局 8 个冰壶的距离。- 两个
for
循环分别读取甲乙双方冰壶距离。 if (a[0] == -1) break;
:检查是否弃权,若弃权则结束比赛。
- 得分计算:
int minA = *std::min_element(a.begin(), a.end());
和int minB = *std::min_element(b.begin(), b.end());
:找出双方冰壶最小距离。- 根据最小距离比较结果,遍历相应方冰壶距离,若满足条件则得分加 1。
- 输出结果:
- 每局输出该局比分,格式为
scoreA:scoreB
。 - 累加每局得分到总得分。
- 最后输出双方总得分,格式为
totalA:totalB
。
- 每局输出该局比分,格式为
简化
cpp
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
int r, ta = 0, tb = 0; std::cin >> r;
for (int i = 0; i < 10; ++i) {
std::vector<int> a(8), b(8);
for (int& x : a) std::cin >> x;
if (a[0] == -1) break;
for (int& x : b) std::cin >> x;
int ma = *std::min_element(a.begin(), a.end());
int mb = *std::min_element(b.begin(), b.end());
int sa = 0, sb = 0;
if (ma < mb) for (int d : a) if (d <= r && d < mb) ++sa;
else if (mb < ma) for (int d : b) if (d <= r && d < ma) ++sb;
std::cout << sa << ":" << sb << '\n';
ta += sa; tb += sb;
}
std::cout << ta << ":" << tb << '\n';
return 0;
}
简化点说明
- 变量命名简化:将
totalA
简化为ta
,totalB
简化为tb
,minA
简化为ma
,minB
简化为mb
,scoreA
简化为sa
,scoreB
简化为sb
,减少变量名长度,使代码更紧凑。 - 输入循环简化:使用范围
for
循环for (int& x : a)
和for (int& x : b)
替代传统的for
循环来读取冰壶距离,代码更简洁。 - 输出换行符简化:将
std::endl
替换为'\n'
,std::endl
除了换行还会刷新输出缓冲区,而'\n'
仅换行,能提高一定的性能。
简单点
cpp
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
int r, sa = 0, sb = 0;
std::cin >> r;
for (int i = 0; i < 10; i++) {
std::vector<int> a(8), b(8);
for (int& x : a) std::cin >> x;
if (a[0] == -1) break;
for (int& x : b) std::cin >> x;
int ma = *min_element(a.begin(), a.end());
int mb = *min_element(b.begin(), b.end());
int ca = 0, cb = 0;
if (ma < mb) for (int x : a) if (x <= r && x < mb) ca++;
else if (mb < ma) for (int x : b) if (x <= r && x < ma) cb++;
std::cout << ca << ":" << cb << '\n';
sa += ca; sb += cb;
}
std::cout << sa << ":" << sb << '\n';
return 0;
}
简化说明
- 变量命名:使用更简短的变量名,比如用
sa
和sb
分别代表甲方和乙方的总得分,ca
和cb
代表每局得分,ma
和mb
代表每方冰壶的最小距离,减少代码的视觉负担。 - 循环使用:继续采用范围
for
循环来读取每方冰壶的距离,让代码更简洁。 - 标准库函数调用:
min_element
函数调用时省略了std::
前缀,因为当前代码的上下文里不会产生命名冲突,这样代码更简洁。 - 输出换行:保持使用
'\n'
进行换行,避免不必要的缓冲区刷新操作。
代码解释
- 输入与初始化:读取规定距离
r
,并初始化甲乙双方总得分sa
和sb
为 0。 - 局数循环:通过
for
循环控制比赛局数,最多进行 10 局。 - 数据读取:使用范围
for
循环读取每局双方 8 个冰壶的距离。若甲方首个输入为 -1,则结束比赛。 - 得分计算:找出双方冰壶最小距离,根据比较结果遍历相应方冰壶距离,满足条件则该局得分加 1。
- 输出结果:每局输出该局比分,累加每局得分到总得分,最后输出双方总得分。
用最基础的c++代码呈现
cpp
#include <iostream>
using namespace std;
int main() {
int r;
cin >> r;
int totalScoreA = 0;
int totalScoreB = 0;
for (int round = 0; round < 10; round++) {
int distancesA[8];
int distancesB[8];
for (int i = 0; i < 8; i++) {
cin >> distancesA[i];
}
if (distancesA[0] == -1) {
break;
}
for (int i = 0; i < 8; i++) {
cin >> distancesB[i];
}
int minDistanceA = distancesA[0];
for (int i = 1; i < 8; i++) {
if (distancesA[i] < minDistanceA) {
minDistanceA = distancesA[i];
}
}
int minDistanceB = distancesB[0];
for (int i = 1; i < 8; i++) {
if (distancesB[i] < minDistanceB) {
minDistanceB = distancesB[i];
}
}
int scoreA = 0;
int scoreB = 0;
if (minDistanceA < minDistanceB) {
for (int i = 0; i < 8; i++) {
if (distancesA[i] <= r && distancesA[i] < minDistanceB) {
scoreA++;
}
}
} else if (minDistanceB < minDistanceA) {
for (int i = 0; i < 8; i++) {
if (distancesB[i] <= r && distancesB[i] < minDistanceA) {
scoreB++;
}
}
}
cout << scoreA << ":" << scoreB << endl;
totalScoreA += scoreA;
totalScoreB += scoreB;
}
cout << totalScoreA << ":" << totalScoreB << endl;
return 0;
}
代码解释:
-
输入读取:
- 首先,程序读取一个整数
r
,这是冰壶比赛中规定的得分距离限制。 - 然后,使用嵌套的
for
循环来读取每一局双方各 8 个冰壶距离目标点P
的距离。若甲方第一局第一个冰壶距离输入为-1
,则表示有一方弃权,比赛停止。
- 首先,程序读取一个整数
-
最小距离计算:
- 对于每一局,分别找出甲方和乙方 8 个冰壶距离目标点
P
的最小距离minDistanceA
和minDistanceB
。这里使用简单的for
循环遍历数组并比较元素大小来实现。
- 对于每一局,分别找出甲方和乙方 8 个冰壶距离目标点
-
得分计算:
- 比较
minDistanceA
和minDistanceB
的大小。如果甲方冰壶最小距离更小,遍历甲方冰壶距离数组,若某个冰壶距离小于等于r
且小于乙方冰壶最小距离,则甲方此冰壶得分,scoreA
加 1;反之,若乙方冰壶最小距离更小,对乙方进行同样的操作。
- 比较
-
输出结果:
- 每一局比赛结束后,输出该局甲乙双方的比分,格式为
scoreA:scoreB
。 - 同时,将该局得分累加到双方的总得分
totalScoreA
和totalScoreB
中。 - 比赛全部结束(达到 10 局或有一方弃权)后,输出双方的最终总得分,格式同样为
totalScoreA:totalScoreB
。
- 每一局比赛结束后,输出该局甲乙双方的比分,格式为
复杂度分析:
- 时间复杂度:对于每一局比赛,计算最小距离和得分的时间复杂度均为 O(8),最多进行 10 局比赛,所以总的时间复杂度为 O(10×8)。
- 空间复杂度:主要使用了两个长度为 8 的数组存储冰壶距离,以及几个整数变量,空间复杂度为 O(8×2)。
简化
cpp
#include <iostream>
int main() {
int r, totalA = 0, totalB = 0;
std::cin >> r;
for (int i = 0; i < 10; i++) {
int a[8], b[8], minA = 10000, minB = 10000, scoreA = 0, scoreB = 0;
for (int j = 0; j < 8; j++) {
std::cin >> a[j];
if (a[0] == -1) return 0;
if (a[j] < minA) minA = a[j];
}
for (int j = 0; j < 8; j++) {
std::cin >> b[j];
if (b[j] < minB) minB = b[j];
}
if (minA < minB) {
for (int j = 0; j < 8; j++) {
if (a[j] <= r && a[j] < minB) scoreA++;
}
} else if (minB < minA) {
for (int j = 0; j < 8; j++) {
if (b[j] <= r && b[j] < minA) scoreB++;
}
}
std::cout << scoreA << ":" << scoreB << std::endl;
totalA += scoreA;
totalB += scoreB;
}
std::cout << totalA << ":" << totalB << std::endl;
return 0;
}
简化说明
- 头文件与命名空间:仅保留了必要的
<iostream>
头文件,使用std::
前缀来调用标准库函数,避免使用using namespace std;
带来的命名冲突风险。...
缩短
cpp
#include <iostream>
int main() {
int r, tA = 0, tB = 0; std::cin >> r;
for (int i = 0; i < 10; i++) {
int a[8], b[8], mA = 1e9, mB = 1e9, sA = 0, sB = 0;
for (int j = 0; j < 8; j++) {
std::cin >> a[j];
if (a[0] == -1) return std::cout << tA << ":" << tB << std::endl, 0;
if (a[j] < mA) mA = a[j];
}
for (int j = 0; j < 8; j++) {
std::cin >> b[j];
if (b[j] < mB) mB = b[j];
}
if (mA < mB) for (int j = 0; j < 8; j++) if (a[j] <= r && a[j] < mB) sA++;
else if (mB < mA) for (int j = 0; j < 8; j++) if (b[j] <= r && b[j] < mA) sB++;
std::cout << sA << ":" << sB << std::endl;
tA += sA; tB += sB;
}
std::cout << tA << ":" << tB << std::endl;
return 0;
}
缩短说明
- 变量命名:将变量名进一步缩短,如
totalA
变为tA
,totalB
变为tB
,minA
变为mA
,minB
变为mB
,scoreA
变为sA
,scoreB
变为sB
,减少字符数量。 - 初始化:将多个变量的声明和初始化合并在一行,减少代码行数。
- 弃权处理:在读取甲方数据时,如果发现
a[0] == -1
,使用逗号表达式直接输出当前总得分并结束程序,简化了弃权逻辑的处理代码。 - 得分计算循环:将得分计算的
for
循环和if
判断合并成一行,减少代码行数。
用初学者能看懂的代码
cpp
#include <iostream>
using namespace std;
int main() {
// 存储规定的距离 r
int r;
// 输入规定的距离 r
cin >> r;
// 记录甲方的总得分
int totalScoreA = 0;
// 记录乙方的总得分
int totalScoreB = 0;
// 进行比赛局数的循环,最多进行 10 局
for (int round = 0; round < 10; round++) {
// 存储甲方每局 8 个冰壶距离目标点的距离
int distancesA[8];
// 存储乙方每局 8 个冰壶距离目标点的距离
int distancesB[8];
// 输入甲方 8 个冰壶的距离
for (int i = 0; i < 8; i++) {
cin >> distancesA[i];
}
// 检查是否有一方弃权,如果甲方第一个冰壶距离为 -1 则表示弃权
if (distancesA[0] == -1) {
break;
}
// 输入乙方 8 个冰壶的距离
for (int i = 0; i < 8; i++) {
cin >> distancesB[i];
}
// 找出甲方 8 个冰壶距离目标点的最小距离
int minDistanceA = distancesA[0];
for (int i = 1; i < 8; i++) {
if (distancesA[i] < minDistanceA) {
minDistanceA = distancesA[i];
}
}
// 找出乙方 8 个冰壶距离目标点的最小距离
int minDistanceB = distancesB[0];
for (int i = 1; i < 8; i++) {
if (distancesB[i] < minDistanceB) {
minDistanceB = distancesB[i];
}
}
// 记录甲方这一局的得分
int scoreA = 0;
// 记录乙方这一局的得分
int scoreB = 0;
// 判断哪一方冰壶离目标点更近
if (minDistanceA < minDistanceB) {
// 甲方冰壶离目标点更近,计算甲方得分
for (int i = 0; i < 8; i++) {
if (distancesA[i] <= r && distancesA[i] < minDistanceB) {
scoreA = scoreA + 1;
}
}
} else if (minDistanceB < minDistanceA) {
// 乙方冰壶离目标点更近,计算乙方得分
for (int i = 0; i < 8; i++) {
if (distancesB[i] <= r && distancesB[i] < minDistanceA) {
scoreB = scoreB + 1;
}
}
}
// 输出这一局甲乙双方的比分
cout << scoreA << ":" << scoreB << endl;
// 累加甲方这一局的得分到总得分
totalScoreA = totalScoreA + scoreA;
// 累加乙方这一局的得分到总得分
totalScoreB = totalScoreB + scoreB;
}
// 输出甲乙双方比赛的最终总得分
cout << totalScoreA << ":" << totalScoreB << endl;
return 0;
}
代码解释
整体思路
这段代码模拟了冰壶比赛的得分计算过程。首先读取规定的距离 r
,然后进行多局比赛的模拟,每局比赛中读取甲乙双方各 8 个冰壶距离目标点的距离,计算每局的得分并输出,最后输出双方的总得分。
代码详细解释
-
输入规定距离
r
cpp
int r; cin >> r;
定义一个整数变量
r
用于存储规定的距离,通过cin
从标准输入读取该值。 -
初始化总得分
cpp
int totalScoreA = 0; int totalScoreB = 0;
分别定义两个整数变量
totalScoreA
和totalScoreB
用于记录甲方和乙方的总得分,并初始化为 0。 -
比赛局数循环
cpp
for (int round = 0; round < 10; round++) { // ... }
使用
for
循环来模拟比赛的局数,最多进行 10 局。 -
每局比赛数据处理
- 定义存储冰壶距离的数组
cpp
int distancesA[8]; int distancesB[8];
分别定义两个长度为 8 的整数数组distancesA
和distancesB
用于存储甲方和乙方每局 8 个冰壶距离目标点的距离。 - 输入甲方冰壶距离
cpp
for (int i = 0; i < 8; i++) { cin >> distancesA[i]; }
使用for
循环从标准输入读取甲方 8 个冰壶的距离,并存储到distancesA
数组中。 - 检查是否弃权
cpp
if (distancesA[0] == -1) { break; }
如果甲方第一个冰壶距离为 -1,则表示有一方弃权,使用break
语句跳出比赛局数循环。 - 输入乙方冰壶距离
cpp
for (int i = 0; i < 8; i++) { cin >> distancesB[i]; }
使用for
循环从标准输入读取乙方 8 个冰壶的距离,并存储到distancesB
数组中。
- 定义存储冰壶距离的数组
-
计算最小距离
- 计算甲方冰壶最小距离
cpp
int minDistanceA = distancesA[0]; for (int i = 1; i < 8; i++) { if (distancesA[i] < minDistanceA) { minDistanceA = distancesA[i]; } }
先将minDistanceA
初始化为甲方第一个冰壶的距离,然后遍历distancesA
数组,将更小的距离更新到minDistanceA
中。 - 计算乙方冰壶最小距离
cpp
int minDistanceB = distancesB[0]; for (int i = 1; i < 8; i++) { if (distancesB[i] < minDistanceB) { minDistanceB = distancesB[i]; } }
同理,计算乙方冰壶的最小距离。
- 计算甲方冰壶最小距离
-
计算每局得分
- 初始化每局得分
cpp
int scoreA = 0; int scoreB = 0;
分别定义两个整数变量scoreA
和scoreB
用于记录甲方和乙方这一局的得分,并初始化为 0。 - 判断哪一方得分
cpp
if (minDistanceA < minDistanceB) { for (int i = 0; i < 8; i++) { if (distancesA[i] <= r && distancesA[i] < minDistanceB) { scoreA = scoreA + 1; } } } else if (minDistanceB < minDistanceA) { for (int i = 0; i < 8; i++) { if (distancesB[i] <= r && distancesB[i] < minDistanceA) { scoreB = scoreB + 1; } } }
如果甲方冰壶最小距离小于乙方,则遍历甲方冰壶距离数组,若某个冰壶距离小于等于r
且小于乙方冰壶最小距离,则甲方这一局该冰壶得分,scoreA
加 1;反之,乙方得分,scoreB
加 1。
- 初始化每局得分
-
输出每局比分和累加总得分
cpp
cout << scoreA << ":" << scoreB << endl; totalScoreA = totalScoreA + scoreA; totalScoreB = totalScoreB + scoreB;
输出这一局甲乙双方的比分,然后将这一局的得分累加到双方的总得分中。
-
输出最终总得分
cpp
cout << totalScoreA << ":" << totalScoreB << endl;
比赛结束后,输出甲乙双方的最终总得分。
复杂度分析
- 时间复杂度:对于每一局比赛,计算最小距离和得分的时间复杂度均为 O(8),最多进行 10 局比赛,所以总的时间复杂度为 O(10×8)。
- 空间复杂度:主要使用了两个长度为 8 的数组存储冰壶距离,以及几个整数变量,空间复杂度为 O(8×2)。...
小学版
cpp
#include <iostream>
using namespace std;
int main() {
// 先准备一个变量 r 来存规定的距离
int r;
cout << "请输入规定的距离 r: ";
cin >> r;
// 甲方和乙方的总得分,一开始都得 0 分
int totalScoreA = 0;
int totalScoreB = 0;
// 比赛最多进行 10 局,用循环来模拟每一局
for (int game = 1; game <= 10; game++) {
cout << "现在是第 " << game << " 局比赛。" << endl;
// 准备两个盒子,一个放甲方 8 个冰壶的距离,一个放乙方 8 个冰壶的距离
int distancesA[8];
int distancesB[8];
// 让小朋友输入甲方 8 个冰壶的距离
cout << "请输入甲方 8 个冰壶距离目标点的距离,用空格分开: ";
for (int i = 0; i < 8; i++) {
cin >> distancesA[i];
}
// 看看是不是有人弃权啦,如果甲方第一个冰壶距离是 -1,就不玩啦
if (distancesA[0] == -1) {
cout << "有一方弃权,比赛结束。" << endl;
break;
}
// 让小朋友输入乙方 8 个冰壶的距离
cout << "请输入乙方 8 个冰壶距离目标点的距离,用空格分开: ";
for (int i = 0; i < 8; i++) {
cin >> distancesB[i];
}
// 找出甲方冰壶里离目标点最近的距离
int minDistanceA = distancesA[0];
for (int i = 1; i < 8; i++) {
if (distancesA[i] < minDistanceA) {
minDistanceA = distancesA[i];
}
}
// 找出乙方冰壶里离目标点最近的距离
int minDistanceB = distancesB[0];
for (int i = 1; i < 8; i++) {
if (distancesB[i] < minDistanceB) {
minDistanceB = distancesB[i];
}
}
// 这一局甲方和乙方的得分,一开始都得 0 分
int scoreA = 0;
int scoreB = 0;
// 看看哪一方的冰壶离目标点更近
if (minDistanceA < minDistanceB) {
// 甲方更近,看看甲方有几个冰壶能得分
for (int i = 0; i < 8; i++) {
if (distancesA[i] <= r && distancesA[i] < minDistanceB) {
scoreA = scoreA + 1;
}
}
} else if (minDistanceB < minDistanceA) {
// 乙方更近,看看乙方有几个冰壶能得分
for (int i = 0; i < 8; i++) {
if (distancesB[i] <= r && distancesB[i] < minDistanceA) {
scoreB = scoreB + 1;
}
}
}
// 告诉小朋友这一局甲乙双方的得分
cout << "第 " << game << " 局比赛,甲方得分: " << scoreA << ",乙方得分: " << scoreB << endl;
// 把这一局的得分加到双方的总得分里
totalScoreA = totalScoreA + scoreA;
totalScoreB = totalScoreB + scoreB;
}
// 比赛结束啦,告诉小朋友甲乙双方的最终总得分
cout << "比赛结束,甲方最终总得分: " << totalScoreA << ",乙方最终总得分: " << totalScoreB << endl;
return 0;
}
代码解释
整体思路
这个代码就像是带着小朋友玩一个冰壶比赛的计分游戏。首先要知道游戏规定的距离 r
,然后进行最多 10 局的比赛。每一局里,让小朋友输入甲方和乙方 8 个冰壶离目标点的距离,看看哪一方的冰壶离得更近,符合条件的冰壶就能得分,最后算出双方的总得分。
详细解释
-
输入规定距离
r
cpp
int r; cout << "请输入规定的距离 r: "; cin >> r;
先和小朋友说要输入一个规定的距离
r
,然后用cin
把小朋友输入的数字存到变量r
里。 -
初始化总得分
cpp
int totalScoreA = 0; int totalScoreB = 0;
甲方和乙方一开始都没有得分,所以总得分都设为 0。
-
比赛局数循环
cpp
for (int game = 1; game <= 10; game++) { // ... }
用
for
循环来模拟比赛的局数,从第 1 局到第 10 局。每一局开始的时候,都会告诉小朋友现在是第几局。 -
每局比赛数据处理
- 准备存储冰壶距离的 “盒子”
cpp
int distancesA[8]; int distancesB[8];
就像准备两个盒子,一个用来放甲方 8 个冰壶的距离,一个用来放乙方 8 个冰壶的距离。 - 输入甲方冰壶距离
cpp
cout << "请输入甲方 8 个冰壶距离目标点的距离,用空格分开: "; for (int i = 0; i < 8; i++) { cin >> distancesA[i]; }
让小朋友输入甲方 8 个冰壶的距离,用for
循环把这些距离一个一个存到distancesA
这个 “盒子” 里。 - 检查是否弃权
cpp
if (distancesA[0] == -1) { cout << "有一方弃权,比赛结束。" << endl; break; }
如果甲方第一个冰壶的距离是 -1,就告诉小朋友有一方弃权了,比赛结束,然后用break
跳出循环。 - 输入乙方冰壶距离
cpp
cout << "请输入乙方 8 个冰壶距离目标点的距离,用空格分开: "; for (int i = 0; i < 8; i++) { cin >> distancesB[i]; }
同样的,让小朋友输入乙方 8 个冰壶的距离,存到distancesB
这个 “盒子” 里。
- 准备存储冰壶距离的 “盒子”
-
计算最小距离
- 找出甲方冰壶的最小距离
cpp
int minDistanceA = distancesA[0]; for (int i = 1; i < 8; i++) { if (distancesA[i] < minDistanceA) { minDistanceA = distancesA[i]; } }
先假设甲方第一个冰壶的距离是最小的,然后一个一个看其他冰壶的距离,如果有更小的,就把最小距离更新成那个更小的值。 - 找出乙方冰壶的最小距离
cpp
int minDistanceB = distancesB[
- 找出甲方冰壶的最小距离
只用int,
cpp
#include <iostream>
int main() {
// 存储规定的距离 r
int r;
std::cin >> r;
// 甲方和乙方的总得分,初始为 0
int totalScoreA = 0;
int totalScoreB = 0;
// 进行比赛局数的循环,最多 10 局
for (int round = 0; round < 10; round++) {
// 甲方和乙方 8 个冰壶的距离
int a1, a2, a3, a4, a5, a6, a7, a8;
int b1, b2, b3, b4, b5, b6, b7, b8;
std::cin >> a1;
// 检查是否弃权
if (a1 == -1) {
break;
}
std::cin >> a2 >> a3 >> a4 >> a5 >> a6 >> a7 >> a8;
std::cin >> b1 >> b2 >> b3 >> b4 >> b5 >> b6 >> b7 >> b8;
// 找出甲方冰壶的最小距离
int minA = a1;
if (a2 < minA) minA = a2;
if (a3 < minA) minA = a3;
if (a4 < minA) minA = a4;
if (a5 < minA) minA = a5;
if (a6 < minA) minA = a6;
if (a7 < minA) minA = a7;
if (a8 < minA) minA = a8;
// 找出乙方冰壶的最小距离
int minB = b1;
if (b2 < minB) minB = b2;
if (b3 < minB) minB = b3;
if (b4 < minB) minB = b4;
if (b5 < minB) minB = b5;
if (b6 < minB) minB = b6;
if (b7 < minB) minB = b7;
if (b8 < minB) minB = b8;
// 这一局甲方和乙方的得分,初始为 0
int scoreA = 0;
int scoreB = 0;
// 计算甲方得分
if (minA < minB) {
if (a1 <= r && a1 < minB) scoreA++;
if (a2 <= r && a2 < minB) scoreA++;
if (a3 <= r && a3 < minB) scoreA++;
if (a4 <= r && a4 < minB) scoreA++;
if (a5 <= r && a5 < minB) scoreA++;
if (a6 <= r && a6 < minB) scoreA++;
if (a7 <= r && a7 < minB) scoreA++;
if (a8 <= r && a8 < minB) scoreA++;
}
// 计算乙方得分
else if (minB < minA) {
if (b1 <= r && b1 < minA) scoreB++;
if (b2 <= r && b2 < minA) scoreB++;
if (b3 <= r && b3 < minA) scoreB++;
if (b4 <= r && b4 < minA) scoreB++;
if (b5 <= r && b5 < minA) scoreB++;
if (b6 <= r && b6 < minA) scoreB++;
if (b7 <= r && b7 < minA) scoreB++;
if (b8 <= r && b8 < minA) scoreB++;
}
// 输出这一局的比分
std::cout << scoreA << ":" << scoreB << std::endl;
// 累加总得分
totalScoreA += scoreA;
totalScoreB += scoreB;
}
// 输出最终总得分
std::cout << totalScoreA << ":" << totalScoreB << std::endl;
return 0;
题目描述 在冰壶比赛中,给出一个目标点P以及一个规定的正整数r。每一局由甲和乙两队轮流投冰壶各8次后,该局比赛结束。此时,哪一方的冰壶最终离目标点P更近,该方得分,另一方不得分。得分方每颗离目标点P距离小于或等于r、位置较另一队所有冰壶都更接近目标点P的冰壶都可以得1分 比赛最多进行10局。双方之间的某局比赛结束后,落后一方可以弃权。此时,比赛不再进行下去 已知每一局结束时,双方的每个冰壶离目标点P的距离以及正整数r,请写一个程序判断两队之间每一局比赛的得分,以及总得分 输入描述 第一行一个正整数r 以下有若干行(不超过20行),每一行8个正整数(之间用一个空格间隔) 第二行的第j个数表示第一局比赛结束时,甲方的第j个冰壶距离目标点P的距离 第三行的第j个数表示第一局比赛结束时,乙方的第j个冰壶距离目标点P的距离 …… 第2k行的第j个数表示第k局比赛结束时,甲方的第j个冰壶距离目标点P的距离 第2k+1行的第j个数表示第k局比赛结束时,乙方的第j个冰壶距离目标点P的距离 如果有一方中途弃权,则最后一行(偶数行)只有一个整数-1,表示此时发生弃权情况 输出描述 输出若干行,每行两个整数,中间以一个冒号间隔,表示每一局比赛甲乙双方的比分(甲得分在前)。最后一行有2个整数,中间以一个冒号间隔,表示甲乙双方比赛的最终得分(甲得分在前) 样例 输入 12 5 60 25 74 71 100 3 93 66 75 70 66 52 73 67 14 93 84 74 99 79 64 89 22 65 5 95 59 80 8 35 61 65 61 49 60 58 50 32 85 68 38 96 38 82 64 26 93 74 92 47 21 97 30 45 78 44 99 90 27 3 46 55 34 49 45 83 3 18 1 67 23 60 47 95 81 17 1 87 85 18 74 74 84 29 20 27 71 37 60 26 56 23 65 67 49 57 7 62 92 52 5 10 69 46 97 88 28 76 27 66 7 89 89 94 31 11 20 1 17 19 48 35 6 77 61 45 21 52 11 76 70 73 99 85 55 90 25 20 7 64 24 94 4 3 43 32 74 10 93 35 77 77 100 63 91 10 73 22 57 输出 2:0 0:2 0:0 0:1 0:0 0:0 1:0 1:0 0:2 1:0 5:5
以下是一个仅使用 int
类型变量实现上述冰壶比赛计分程序的代码:
cpp
#include <iostream>
int main() {
int r;
std::cin >> r;
int totalScoreA = 0;
int totalScoreB = 0;
for (int round = 0; round < 10; round++) {
int a1, a2, a3, a4, a5, a6, a7, a8;
std::cin >> a1;
if (a1 == -1) {
break;
}
std::cin >> a2 >> a3 >> a4 >> a5 >> a6 >> a7 >> a8;
int b1, b2, b3, b4, b5, b6, b7, b8;
std::cin >> b1 >> b2 >> b3 >> b4 >> b5 >> b6 >> b7 >> b8;
int minA = a1;
if (a2 < minA) minA = a2;
if (a3 < minA) minA = a3;
if (a4 < minA) minA = a4;
if (a5 < minA) minA = a5;
if (a6 < minA) minA = a6;
if (a7 < minA) minA = a7;
if (a8 < minA) minA = a8;
int minB = b1;
if (b2 < minB) minB = b2;
if (b3 < minB) minB = b3;
if (b4 < minB) minB = b4;
if (b5 < minB) minB = b5;
if (b6 < minB) minB = b6;
if (b7 < minB) minB = b7;
if (b8 < minB) minB = b8;
int scoreA = 0;
int scoreB = 0;
if (minA < minB) {
if (a1 <= r && a1 < minB) scoreA++;
if (a2 <= r && a2 < minB) scoreA++;
if (a3 <= r && a3 < minB) scoreA++;
if (a4 <= r && a4 < minB) scoreA++;
if (a5 <= r && a5 < minB) scoreA++;
if (a6 <= r && a6 < minB) scoreA++;
if (a7 <= r && a7 < minB) scoreA++;
if (a8 <= r && a8 < minB) scoreA++;
} else if (minB < minA) {
if (b1 <= r && b1 < minA) scoreB++;
if (b2 <= r && b2 < minA) scoreB++;
if (b3 <= r && b3 < minA) scoreB++;
if (b4 <= r && b4 < minA) scoreB++;
if (b5 <= r && b5 < minA) scoreB++;
if (b6 <= r && b6 < minA) scoreB++;
if (b7 <= r && b7 < minA) scoreB++;
if (b8 <= r && b8 < minA) scoreB++;
}
std::cout << scoreA << ":" << scoreB << std::endl;
totalScoreA += scoreA;
totalScoreB += scoreB;
}
std::cout << totalScoreA << ":" << totalScoreB << std::endl;
return 0;
}
代码解释:
-
输入处理:
- 首先读取一个整数
r
,它代表规定的得分距离限制。 - 在每一局比赛中,先读取甲方的 8 个冰壶距离目标点
P
的距离,若第一个输入为-1
,则表示有一方弃权,比赛终止。接着读取乙方的 8 个冰壶距离。
- 首先读取一个整数
-
最小距离计算:
- 对于甲方的 8 个冰壶距离,通过一系列的
if
语句比较找出最小距离minA
。 - 同样地,对于乙方的 8 个冰壶距离,找出最小距离
minB
。
- 对于甲方的 8 个冰壶距离,通过一系列的
-
得分计算:
- 比较
minA
和minB
的大小。如果minA < minB
,说明甲方冰壶整体离目标点更近,然后依次检查甲方每个冰壶的距离是否小于等于r
且小于minB
,若满足条件则甲方此冰壶得分,scoreA
加 1。 - 若
minB < minA
,则乙方冰壶整体离目标点更近,对乙方的冰壶进行类似的得分判断,scoreB
相应增加。
- 比较
-
输出结果:
- 每一局比赛结束后,输出该局甲乙双方的比分,格式为
scoreA:scoreB
。 - 同时将该局得分累加到双方的总得分
totalScoreA
和totalScoreB
中。 - 当比赛结束(达到 10 局或出现弃权情况),输出双方的最终总得分,格式为
totalScoreA:totalScoreB
。
- 每一局比赛结束后,输出该局甲乙双方的比分,格式为
复杂度分析:
- 时间复杂度:每一局比赛中,计算最小距离和得分的操作都需要对 8 个冰壶距离进行比较,时间复杂度为 O(8)。最多进行 10 局比赛,所以总的时间复杂度为 O(10×8)。
- 空间复杂度:只使用了固定数量的
int
类型变量来存储冰壶距离、最小距离、得分等信息,空间复杂度为 O(1)。
用可达鸭编程c++的版本来写
可达鸭编程风格通常是比较通俗易懂、适合初学者理解的,以下是结合可达鸭编程风格,用 C++ 实现冰壶比赛计分程序的代码:
cpp
#include <iostream>
using namespace std;
int main() {
// 可达鸭告诉你,先把规定的距离 r 存起来哟
int r;
cout << "可达鸭要知道比赛规定的距离 r 是多少呀,请输入:";
cin >> r;
// 甲方和乙方的总得分,一开始都没有得分呢,所以是 0
int totalScoreA = 0;
int totalScoreB = 0;
// 比赛最多进行 10 局,可达鸭开始一局一局数啦
for (int round = 1; round <= 10; round++) {
cout << "现在是第 " << round << " 局比赛咯!" << endl;
// 可达鸭准备记录甲方 8 个冰壶的距离啦
int a1, a2, a3, a4, a5, a6, a7, a8;
cout << "快告诉可达鸭甲方 8 个冰壶离目标点 P 的距离,用空格分开哟:";
cin >> a1;
// 可达鸭看看有没有人弃权呀
if (a1 == -1) {
cout << "哎呀,有一方弃权啦,比赛结束咯!" << endl;
break;
}
cin >> a2 >> a3 >> a4 >> a5 >> a6 >> a7 >> a8;
// 可达鸭再记录乙方 8 个冰壶的距离
int b1, b2, b3, b4, b5, b6, b7, b8;
cout << "接着说说乙方 8 个冰壶离目标点 P 的距离,用空格分开哈:";
cin >> b1 >> b2 >> b3 >> b4 >> b5 >> b6 >> b7 >> b8;
// 可达鸭来找找甲方冰壶里离目标点 P 最近的距离
int minA = a1;
if (a2 < minA) minA = a2;
if (a3 < minA) minA = a3;
if (a4 < minA) minA = a4;
if (a5 < minA) minA = a5;
if (a6 < minA) minA = a6;
if (a7 < minA) minA = a7;
if (a8 < minA) minA = a8;
// 可达鸭再找找乙方冰壶里离目标点 P 最近的距离
int minB = b1;
if (b2 < minB) minB = b2;
if (b3 < minB) minB = b3;
if (b4 < minB) minB = b4;
if (b5 < minB) minB = b5;
if (b6 < minB) minB = b6;
if (b7 < minB) minB = b7;
if (b8 < minB) minB = b8;
// 这一局甲方和乙方的得分,一开始都没有得分,是 0
int scoreA = 0;
int scoreB = 0;
// 可达鸭看看哪一方的冰壶离目标点 P 更近呢
if (minA < minB) {
// 甲方更近,可达鸭算算甲方有几个冰壶能得分
if (a1 <= r && a1 < minB) scoreA++;
if (a2 <= r && a2 < minB) scoreA++;
if (a3 <= r && a3 < minB) scoreA++;
if (a4 <= r && a4 < minB) scoreA++;
if (a5 <= r && a5 < minB) scoreA++;
if (a6 <= r && a6 < minB) scoreA++;
if (a7 <= r && a7 < minB) scoreA++;
if (a8 <= r && a8 < minB) scoreA++;
} else if (minB < minA) {
// 乙方更近,可达鸭算算乙方有几个冰壶能得分
if (b1 <= r && b1 < minA) scoreB++;
if (b2 <= r && b2 < minA) scoreB++;
if (b3 <= r && b3 < minA) scoreB++;
if (b4 <= r && b4 < minA) scoreB++;
if (b5 <= r && b5 < minA) scoreB++;
if (b6 <= r && b6 < minA) scoreB++;
if (b7 <= r && b7 < minA) scoreB++;
if (b8 <= r && b8 < minA) scoreB++;
}
// 可达鸭告诉你们这一局甲乙双方的得分啦
cout << "第 " << round << " 局比赛,甲方得分:" << scoreA << ",乙方得分:" << scoreB << endl;
// 把这一局的得分加到双方的总得分里哟
totalScoreA += scoreA;
totalScoreB += scoreB;
}
// 比赛结束啦,可达鸭公布甲乙双方的最终总得分
cout << "比赛结束咯!甲方最终总得分:" << totalScoreA << ",乙方最终总得分:" << totalScoreB << endl;
return 0;
}
代码解释
整体思路
这个程序模拟了冰壶比赛的计分过程,通过用户输入每局比赛双方冰壶距离目标点的距离,根据规则计算每局得分和总得分。
详细步骤
- 输入规定距离
r
:程序会提示用户输入比赛规定的距离r
,并将其存储在变量r
中。 - 初始化总得分:将甲方和乙方的总得分
totalScoreA
和totalScoreB
初始化为 0。 - 比赛局数循环:使用
for
循环从第 1 局到第 10 局进行比赛模拟。每局开始时会提示当前是第几局。 - 输入冰壶距离:分别提示用户输入甲方和乙方 8 个冰壶离目标点
P
的距离。如果甲方第一个输入为-1
,则表示有一方弃权,比赛结束。 - 计算最小距离:分别找出甲方和乙方冰壶中离目标点
P
最近的距离minA
和minB
。 - 计算每局得分:比较
minA
和minB
的大小,若minA < minB
,则计算甲方得分;若minB < minA
,则计算乙方得分。 - 输出每局比分:输出每一局甲乙双方的得分情况。
- 累加总得分:将每一局的得分累加到双方的总得分中。
- 输出最终总得分:比赛结束后,输出甲乙双方的最终总得分。
这样的代码风格更像是可达鸭在和你交流,用比较亲切、易懂的语言引导你完成整个冰壶比赛计分的过程,适合初学者理解。
在冰壶比赛中,给出一个目标点P以及一个规定的正整数r。每一局由甲和乙两队轮流投冰壶各8次后,该局比赛结束。此时,哪一方的冰壶最终离目标点P更近,该方得分,另一方不得分。得分方每颗离目标点P距离小于或等于r、位置较另一队所有冰壶都更接近目标点P的冰壶都可以得1分 比赛最多进行10局。双方之间的某局比赛结束后,落后一方可以弃权。此时,比赛不再进行下去 已知每一局结束时,双方的每个冰壶离目标点P的距离以及正整数r,请写一个程序判断两队之间每一局比赛的得分,以及总得分 输入描述 第一行一个正整数r 以下有若干行(不超过20行),每一行8个正整数(之间用一个空格间隔) 第二行的第j个数表示第一局比赛结束时,甲方的第j个冰壶距离目标点P的距离 第三行的第j个数表示第一局比赛结束时,乙方的第j个冰壶距离目标点P的距离 …… 第2k行的第j个数表示第k局比赛结束时,甲方的第j个冰壶距离目标点P的距离 第2k+1行的第j个数表示第k局比赛结束时,乙方的第j个冰壶距离目标点P的距离 如果有一方中途弃权,则最后一行(偶数行)只有一个整数-1,表示此时发生弃权情况 输出描述 输出若干行,每行两个整数,中间以一个冒号间隔,表示每一局比赛甲乙双方的比分(甲得分在前)。最后一行有2个整数,中间以一个冒号间隔,表示甲乙双方比赛的最终得分(甲得分在前) 样例 输入 12 5 60 25 74 71 100 3 93 66 75 70 66 52 73 67 14 93 84 74 99 79 64 89 22 65 5 95 59 80 8 35 61 65 61 49 60 58 50 32 85 68 38 96 38 82 64 26 93 74 92 47 21 97 30 45 78 44 99 90 27 3 46 55 34 49 45 83 3 18 1 67 23 60 47 95 81 17 1 87 85 18 74 74 84 29 20 27 71 37 60 26 56 23 65 67 49 57 7 62 92 52 5 10 69 46 97 88 28 76 27 66 7 89 89 94 31 11 20 1 17 19 48 35 6 77 61 45 21 52 11 76 70 73 99 85 55 90 25 20 7 64 24 94 4 3 43 32 74 10 93 35 77 77 100 63 91 10 73 22 57 输出 2:0 0:2 0:0 0:1 0:0 0:0 1:0 1:0 0:2 1:0 5:5
分享
以下是一个使用 Python 实现的解决方案:
python
# 读取规定的距离 r
r = int(input())
# 初始化甲方和乙方的总得分
total_score_a = 0
total_score_b = 0
# 用于存储每一局的比分
scores = []
# 最多进行 10 局比赛
for _ in range(10):
try:
# 读取甲方 8 个冰壶距离目标点 P 的距离
distances_a = list(map(int, input().split()))
# 检查是否有一方弃权
if len(distances_a) == 1 and distances_a[0] == -1:
break
# 读取乙方 8 个冰壶距离目标点 P 的距离
distances_b = list(map(int, input().split()))
# 找出甲方冰壶的最小距离
min_distance_a = min(distances_a)
# 找出乙方冰壶的最小距离
min_distance_b = min(distances_b)
# 初始化本局甲方和乙方的得分
score_a = 0
score_b = 0
# 判断哪一方的冰壶离目标点 P 更近
if min_distance_a < min_distance_b:
# 甲方的冰壶更近,计算甲方得分
for distance in distances_a:
if distance <= r and distance < min_distance_b:
score_a += 1
elif min_distance_b < min_distance_a:
# 乙方的冰壶更近,计算乙方得分
for distance in distances_b:
if distance <= r and distance < min_distance_a:
score_b += 1
# 存储本局比分
scores.append((score_a, score_b))
# 累加本局得分到总得分
total_score_a += score_a
total_score_b += score_b
except EOFError:
break
# 输出每一局的比分
for score_a, score_b in scores:
print(f"{score_a}:{score_b}")
# 输出最终总得分
print(f"{total_score_a}:{total_score_b}")
代码解释:
-
读取输入:
- 首先读取规定的距离
r
。 - 然后通过循环最多进行 10 局比赛,每局比赛中读取甲方和乙方 8 个冰壶距离目标点
P
的距离。 - 如果读取到只有一个整数
-1
,则表示有一方弃权,停止比赛。
- 首先读取规定的距离
-
计算每局得分:
- 找出甲方和乙方冰壶的最小距离
min_distance_a
和min_distance_b
。 - 如果甲方冰壶的最小距离更小,遍历甲方的冰壶距离,若某个冰壶距离小于等于
r
且小于乙方冰壶的最小距离,则甲方此冰壶得分。 - 同理,如果乙方冰壶的最小距离更小,遍历乙方的冰壶距离计算得分。
- 找出甲方和乙方冰壶的最小距离
-
存储和输出结果:
- 每局比赛结束后,将本局的比分存储在
scores
列表中,并累加到总得分中。 - 最后,输出每一局的比分和最终的总得分。
- 每局比赛结束后,将本局的比分存储在
复杂度分析:
- 时间复杂度:每一局比赛中,计算最小距离和得分的时间复杂度均为 O(8),最多进行 10 局比赛,所以总的时间复杂度为 O(10×8)。
- 空间复杂度:主要使用了一个列表来存储每一局的比分,空间复杂度为 O(10)。
c++更通俗易懂
cpp
#include <iostream>
using namespace std;
int main() {
// 读取规定的正整数 r
int r;
cin >> r;
// 初始化甲方和乙方的总得分
int totalScoreA = 0;
int totalScoreB = 0;
// 最多进行 10 局比赛
for (int round = 0; round < 10; round++) {
// 存储甲方 8 个冰壶的距离
int distancesA[8];
// 存储乙方 8 个冰壶的距离
int distancesB[8];
// 读取甲方 8 个冰壶的距离
for (int i = 0; i < 8; i++) {
cin >> distancesA[i];
}
// 检查是否有一方弃权
if (distancesA[0] == -1) {
break;
}
// 读取乙方 8 个冰壶的距离
for (int i = 0; i < 8; i++) {
cin >> distancesB[i];
}
// 找出甲方冰壶的最小距离
int minDistanceA = distancesA[0];
for (int i = 1; i < 8; i++) {
if (distancesA[i] < minDistanceA) {
minDistanceA = distancesA[i];
}
}
// 找出乙方冰壶的最小距离
int minDistanceB = distancesB[0];
for (int i = 1; i < 8; i++) {
if (distancesB[i] < minDistanceB) {
minDistanceB = distancesB[i];
}
}
// 初始化本局甲方和乙方的得分
int scoreA = 0;
int scoreB = 0;
// 判断哪一方的冰壶离目标点 P 更近
if (minDistanceA < minDistanceB) {
// 甲方的冰壶更近,计算甲方得分
for (int i = 0; i < 8; i++) {
if (distancesA[i] <= r && distancesA[i] < minDistanceB) {
scoreA++;
}
}
} else if (minDistanceB < minDistanceA) {
// 乙方的冰壶更近,计算乙方得分
for (int i = 0; i < 8; i++) {
if (distancesB[i] <= r && distancesB[i] < minDistanceA) {
scoreB++;
}
}
}
// 输出本局甲乙双方的比分
cout << scoreA << ":" << scoreB << endl;
// 累加本局得分到总得分
totalScoreA += scoreA;
totalScoreB += scoreB;
}
// 输出甲乙双方的最终总得分
cout << totalScoreA << ":" << totalScoreB << endl;
return 0;
}
代码解释
1. 输入读取
cpp
int r;
cin >> r;
首先,程序会读取一个整数 r
,这个 r
是比赛规定的距离,用于判断冰壶是否能得分。
2. 总得分初始化
cpp
int totalScoreA = 0;
int totalScoreB = 0;
定义两个变量 totalScoreA
和 totalScoreB
分别用来记录甲方和乙方的总得分,初始值都设为 0。
3. 比赛局数循环
cpp
for (int round = 0; round < 10; round++) {
// ...
}
使用 for
循环来模拟比赛的局数,最多进行 10 局。
4. 每局冰壶距离读取
cpp
int distancesA[8];
int distancesB[8];
for (int i = 0; i < 8; i++) {
cin >> distancesA[i];
}
if (distancesA[0] == -1) {
break;
}
for (int i = 0; i < 8; i++) {
cin >> distancesB[i];
}
- 定义两个长度为 8 的数组
distancesA
和distancesB
分别存储甲方和乙方 8 个冰壶的距离。 - 先读取甲方 8 个冰壶的距离,如果甲方第一个冰壶的距离是
-1
,表示有一方弃权,使用break
语句跳出循环,结束比赛。 - 若没有弃权,接着读取乙方 8 个冰壶的距离。
5. 计算最小距离
cpp
int minDistanceA = distancesA[0];
for (int i = 1; i < 8; i++) {
if (distancesA[i] < minDistanceA) {
minDistanceA = distancesA[i];
}
}
int minDistanceB = distancesB[0];
for (int i = 1; i < 8; i++) {
if (distancesB[i] < minDistanceB) {
minDistanceB = distancesB[i];
}
}
- 对于甲方的冰壶距离数组
distancesA
,先假设第一个元素是最小距离,然后遍历数组,若发现更小的距离,就更新minDistanceA
。 - 对乙方的冰壶距离数组
distancesB
做同样的操作,得到乙方冰壶的最小距离minDistanceB
。
6. 计算本局得分
cpp
int scoreA = 0;
int scoreB = 0;
if (minDistanceA < minDistanceB) {
for (int i = 0; i < 8; i++) {
if (distancesA[i] <= r && distancesA[i] < minDistanceB) {
scoreA++;
}
}
} else if (minDistanceB < minDistanceA) {
for (int i = 0; i < 8; i++) {
if (distancesB[i] <= r && distancesB[i] < minDistanceA) {
scoreB++;
}
}
}
- 初始化本局甲方和乙方的得分
scoreA
和scoreB
为 0。 - 比较
minDistanceA
和minDistanceB
的大小:- 如果
minDistanceA < minDistanceB
,说明甲方的冰壶整体离目标点更近,遍历甲方的冰壶距离数组,若某个冰壶的距离小于等于r
且小于乙方冰壶的最小距离,甲方这局此冰壶得分,scoreA
加 1。 - 如果
minDistanceB < minDistanceA
,则乙方的冰壶整体离目标点更近,对乙方的冰壶距离数组做类似操作,scoreB
加 1。
- 如果
7. 输出本局比分并累加总得分
cpp
cout << scoreA << ":" << scoreB << endl;
totalScoreA += scoreA;
totalScoreB += scoreB;
- 输出本局甲乙双方的比分,格式为
scoreA:scoreB
。 - 将本局得分累加到双方的总得分中。
8. 输出最终总得分
cpp
cout << totalScoreA << ":" << totalScoreB << endl;