冰壶比赛 扑克洗牌问题

某城市最高的建筑只有一部电梯。一份电梯升降任务表由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)

代码解释:

  1. 输入处理
    • 使用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;
}

代码解释:

  1. 输入循环

    • 程序使用 while (true) 构建一个无限循环,持续读取输入。
    • 每次循环开始时,读取一个整数 N,它代表任务表中楼层的数量。
    • 若 N 为 0,则使用 break 语句跳出循环,结束输入处理。
  2. 任务处理

    • 对于每组非零的 N,程序会初始化总时间 total_time 为 0,并设定当前楼层 current_floor 为 0
    • 通过 for 循环读取 N 个目标楼层号。
    • 对于每个目标楼层,计算与当前楼层的差值 diff
    • 如果 diff 大于 0,表示电梯上升,总时间加上 diff * 6;如果 diff 小于等于 0,表示电梯下降,总时间加上 (-diff) * 4
    • 每次到达目标楼层后,总时间加上停留的 5 秒钟。
    • 最后更新当前楼层为目标楼层。
  3. 输出结果

    • 每组任务处理完成后,程序会输出完成该组任务所花费的总时间,然后换行等待下一组输入。

复杂度分析:

  • 时间复杂度: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;
}

代码解释:

  1. shuffle 函数:该函数接受一个 std::vector<int> 类型的参数 cards,表示当前的牌序。函数内部通过循环将后 n 张牌和前 n 张牌交叉组合,生成新的牌序,并将其存储在 newCards 中返回。
  2. printCards 函数:该函数接受一个 std::vector<int> 类型的参数 cards,用于打印当前牌的顺序。在打印过程中,使用空格分隔每张牌,并在最后换行。
  3. isOriginalOrder 函数:该函数接受两个 std::vector<int> 类型的参数 cards 和 original,用于检查当前牌序是否与初始牌序相同。通过遍历两张牌序的每个元素进行比较,如果有任何元素不同,则返回 false,否则返回 true
  4. 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
12
24
33
46
510
74

可以发现,洗牌次数 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}")

代码解释:

  1. 输入读取:通过 input() 函数读取用户输入的整数 n
  2. 初始化牌...

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;
}

代码解释

  1. 输入处理
    • 程序开始时,从标准输入读取一个整数 n,它代表了牌的数量的一半(总共有 2 * n 张牌)。
  2. 牌序初始化
    • 创建一个 std::vector<int> 类型的 cards 数组,用于存储牌的顺序。通过循环将牌从 1 到 2 * n 依次放入数组中,同时将这个初始牌序复制给 originalCards,用于后续比较是否恢复到初始状态。
  3. 初始牌序输出
    • 调用 printCards 函数打印初始的牌序。该函数会遍历 cards 数组并按格式输出。
  4. 洗牌循环
    • 使用 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;
}

简化点说明

  1. printCards 函数:使用范围 for 循环来遍历 cards 向量,减少了代码量,更简洁地实现了牌序的打印。
  2. 变量声明和初始化:在 main 函数中,将 cards 和 original 向量的声明和初始化合并在一起,代码更紧凑。
  3. do-while 循环
    • 直接在循环体中使用 ++m 来增加洗牌次数并输出,避免了额外的 m++ 语句。
    • 循环条件使用 cards != original 直接比较向量是否相等,代码更加直观。

代码解释

  1. 输入处理:从标准输入读取整数 n,确定牌的数量。
  2. 牌序初始化:创建 cards 和 original 向量,将其初始化为 1 到 2 * n 的顺序。
  3. 初始牌序输出:调用 printCards 函数打印初始牌序。
  4. 洗牌循环
    • 在 do-while 循环中,每次进行洗牌操作,生成新的牌序 newCards
    • 将 newCards 赋值给 cards,更新当前牌序。
    • 打印当前洗牌次数和新的牌序。
    • 循环条件是 cards 不等于 original,即未恢复到初始顺序。
  5. 输出结果:循环结束后,输出总的洗牌次数 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;
}

代码解释:

  1. 输入部分

    • 程序开始运行后,会从键盘读取一个整数 n,它代表了总牌数的一半,也就是有 2 * n 张牌。
  2. 初始化牌的顺序
    -...

简化

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;
        }
    }
}

代码简化说明

  1. 减少函数使用:去掉了原代码中的 printCardsshuffle 和 isSame 函数,将这些函数的功能直接集成到 main 函数中,使代码结构更简单,更适合小学级别的理解。
  2. 初始化与打印合并:在初始化牌序数组的同时,直接将初始牌序打印出来,减少了额外的循环和代码量。
  3. 洗牌操作直接实现:在 do - while 循环中直接进行洗牌操作,避免了函数调用的复杂性。
  4. 顺序检查逻辑内联:将检查是否回到初始顺序的逻辑直接写在 do - while 循环内部,不使用额外的函数。

代码解释

  1. 输入读取:从标准输入读取一个整数 n,表示牌的数量的一半(总共 2 * n 张牌)。
  2. 初始化牌序:创建两个数组 cards 和 original 来存储当前牌序和初始牌序,并将其初始化为 1 到 2 * n 的顺序,同时打印初始牌序。
  3. 洗牌循环
    • 使用 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,然后模拟洗牌过程,每次洗牌后检查牌序是否回到初始状态,若回到初始状态则停止洗牌并输出总的洗牌次数。

代码详细解释

  1. 头文件和命名空间

    cpp

    #include<bits/stdc++.h>
    using namespace std;
    
     
    • #include<bits/stdc++.h>:这是一个非标准的头文件,它包含了所有标准库的头文件,方便编写代码时无需逐个包含所需的头文件,但在一些竞赛环境外不建议使用,因为它会增加编译时间且可能导致代码的可移植性问题。
    • using namespace std;:使用标准命名空间,这样在代码中使用标准库的类和函数时可以省略 std:: 前缀。
  2. 主函数和变量定义

    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
  3. 初始化牌序并输出初始状态

    cpp

    for(int i=1;i<=2*n;i++){
        a[i]=i;
        cout<<a[i]<<" ";
    } 
    cout<<endl;
    
     
    • 通过循环将数组 a 初始化为 1 到 2n 的顺序,这是初始的牌序。
    • 同时将初始牌序输出,每个牌编号之间用空格分隔,最后换行。
  4. 洗牌循环

    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 数组的奇数位置。
  5. 更新牌序、输出洗牌结果并检查是否回到初始状态

    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,说明牌序已经回到初始状态,退出循环。
  6. 输出总的洗牌次数

    cpp

    cout<<"m="<<cnt;
    
     
    • 输出总的洗牌次数。

代码优化建议

  1. 头文件:建议使用具体的标准库头文件,如 #include <iostream>,避免使用 #include<bits/stdc++.h>
  2. 数组大小:可以考虑使用动态数组(如 std::vector)来避免固定大小数组可能带来的空间浪费和越界风险。
  3. 代码可读性:可以将洗牌操作、检查是否回到初始状态等功能封装成独立的函数,提高代码的可读性和可维护性。

复杂度分析

  • 时间复杂度:每次洗牌操作需要遍历 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;
}

简化说明

  1. 减少变量:去掉了不必要的变量 xy 和 flag,直接在合适的地方进行逻辑处理,让代码更简洁。
  2. 合并循环:将原本分开为两个循环给 b 数组赋值的操作,合并到一个循环中,减少代码冗余。
  3. 简化逻辑判断:将判断是否回到初始顺序的逻辑与输出新牌序的循环结合在一起,通过一个布尔变量 isOriginal 来标记是否回到初始状态。

代码解释

  1. 输入和初始化
    • 从标准输入读取 n
    • 初始化 cards 数组为初始牌序,同时输出初始牌序。
  2. 洗牌循环
    • 在 while (true) 循环中进行洗牌操作。
    • 每次洗牌时,根据规则生成新的牌序存于 newCards 数组。
    • 增加洗牌次数 shuffleCount 并输出当前洗牌次数。
    • 在输出新牌序的同时检查是否回到初始顺序,如果有一张牌位置不对,isOriginal 就设为 false
    • 如果 isOriginal 为 true,说明回到初始顺序,跳出循环。
  3. 输出结果:输出总的洗牌次数。

#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; }

以下是对这段代码的简化和优化分析,我们会尽量保持代码逻辑不变,同时减少代码冗余,提高可读性。

简化思路

  1. 减少不必要的变量:原代码中 x 和 y 用于控制新数组 b 的索引,可直接通过计算来确定索引,无需额外变量。
  2. 合并循环:可以将赋值给新数组 b 的两个循环合并为一个,使代码更简洁。
  3. 优化判断逻辑:将判断是否回到初始状态的逻辑与赋值和输出操作结合,减少代码量。

简化后的代码

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;
}

代码解释

  1. 输入与初始化

    • 从标准输入读取 n,它表示牌数量的一半。
    • 定义数组 cards 用于存储牌的顺序,通过循环将其初始化为 1 到 2 * n 的顺序,并输出初始牌序。
  2. 洗牌循环

    • 使用 while (true) 构建一个无限循环,在每次循环中进行洗牌操作。
    • 定义 newCards 数组用于存储洗牌后的牌序。
    • 通过一个循环完成洗牌操作,将后 n 张牌和前 n 张牌交叉放入 newCards 数组。
    • 增加洗牌次数 shuffleCount 并输出当前洗牌次数。
  3. 检查与更新

    • 遍历 newCards 数组,输出新的牌序,同时将 newCards 的值赋给 cards
    • 在遍历过程中,检查是否回到初始状态,如果有任何一张牌的位置不对,将 isOriginal 标记为 false
    • 如果 isOriginal 为 true,说明回到了初始状态,使用 break 跳出循环。
  4. 输出结果

    • 循环结束后,输出总的洗牌次数。

复杂度分析

  • 时间复杂度:每次洗牌和检查是否回到初始状态都需要遍历 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;
}

代码解释:

  1. 输入与初始牌序输出
    • 读取 n 后,使用一个 for 循环初始化数组 a 为初始牌序,同时将初始牌序输出,每个元素间用空格分隔,最后换行。
  2. 洗牌循环
    • 在 while (1) 无限循环中进行洗牌操作。
    • 每次循环创建数组 b 存储洗牌后的牌序,通过一个 for 循环完成洗牌规则。
    • 增加洗牌次数 cnt 并输出当前洗牌次数。
  3. 检查与更新
    • 另一个 for 循环输出新牌序,更新 a 数组,同时使用逻辑与 &= 操作符检查是否回到初始状态。
    • 如果 flag 为 true,说明回到初始状态,跳出循环。
  4. 输出结果
    • 循环结束后输出总的洗牌次数。

简化

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;
}

简化点说明

  1. 命名空间:使用 std:: 限定符而不是 using namespace std;,避免命名冲突,虽然代码量稍增,但更规范。
  2. 变量命名:把 cnt 改为 times,更具可读性,让人一眼就知道这是记录洗牌次数的变量;a 数组改为 cardsb 数组改为 newCards,能清晰体现数组用途。
  3. 代码逻辑
    • 减少不必要的变量,像原代码里用于控制数组索引的 x 和 y 就去掉了,直接通过计算得到索引。
    • 把赋值给新数组的两个循环合并成一个,使代码更简洁。
    • 将判断是否回到初始状态的逻辑与输出新牌序的循环结合,减少代码重复。
  4. 输出格式:在输出元素时,通过 i < 2 * n ? " " : "\n" 这种简洁的方式控制空格和换行,让代码更紧凑。

代码解释

  1. 输入与初始化
    • 从标准输入读取 n,表示牌数量的一半。
    • 用 for 循环将 cards 数组初始化为 1 到 2 * n 的顺序,同时输出初始牌序。
  2. 洗牌循环
    • while (true) 构成无限循环,在每次循环中进行洗牌操作。
    • 创建 newCards 数组存储洗牌后的牌序,通过 for 循环按洗牌规则填充。
    • 增加 times 计数并输出当前洗牌次数。
  3. 检查与更新
    • 另一个 for 循环输出新牌序,更新 cards 数组,同时检查是否回到初始状态。若有牌位置不对,isOriginal 设为 false
    • 若 isOriginal 为 true,说明回到初始状态,跳出循环。
  4. 输出结果:循环结束后输出总的洗牌次数。

只用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;
}

代码解释:

  1. 头文件和主函数声明

    cpp

    #include <iostream>
    int main() {
    
     

    包含标准输入输出流的头文件,并开始主函数。

  2. 变量定义、输入和初始牌序输出

    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 数组为初始牌序,同时输出初始牌序,每个元素之间用空格分隔,最后一个元素后换行。
  3. 洗牌循环

    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 数组。
  4. 输出洗牌次数、新牌序并检查是否回到初始状态

    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
  5. 结束循环和输出总洗牌次数

    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;
}

进一步简化说明

  1. 数组初始化:使用花括号 {} 对数组 a 和 b 进行初始化,在 C++ 里这是一种简洁的默认初始化方式。
  2. for 循环简化:在两个 for 循环的条件判断和迭代部分做了简化,把 i 的自增操作与输出逻辑合并在一起,减少了代码量。
  3. 布尔变量缩写:把 same 变量缩写成 s,进一步压缩代码长度。
  4. 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 变量被赋值为 trueif 语句判断 isTrue 的值为真,所以会执行其内部的输出语句。

2. Java

Java 同样有布尔类型 booleantrue 是该类型的一个合法值,常用于条件判断和循环控制。

java

public class Main {
    public static void main(String[] args) {
        boolean condition = true;
        if (condition) {
            System.out.println("The condition is true.");
        }
    }
}

这里 condition 变量的值为 trueif 语句会因为条件为真而执行相应的输出操作。

3. Python

Python 中布尔类型是 boolTrue(注意首字母大写)是布尔类型的真值,常被用于逻辑判断。

python

condition = True
if condition:
    print("The condition is true.")

在这个 Python 代码片段中,condition 被赋值为 Trueif 语句会基于此执行后续的打印操作。

4. JavaScript

JavaScript 也支持布尔类型,true 是布尔值之一,广泛应用于逻辑判断和流程控制。

javascript

let isTrue = true;
if (isTrue) {
    console.log("The condition is true.");
}

上述 JavaScript 代码中,isTrue 变量的值为 trueif 语句的条件满足,会执行内部的 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;
}

代码解释:

  1. 输入读取

    • 首先读取正整数 r,它是规定的得分距离限制。
    • 然后进入一个无限循环,每次循环读取甲方和乙方在一局中每个冰壶距离目标点 P 的距离,存储在 distances_a 和 distances_b 向量中。
    • 如果读取到的甲方第一个距离为 -1,则表示有一方弃权,跳出循环。
  2. 计算每局得分

    • 使用 std::min_element 函数找出乙方和甲方冰壶的最小距离 min_distance_b 和 min_distance_a
    • 如果甲方最小距离小于乙方,遍历甲方的冰壶距离,若距离小于等于 r 且小于乙方最小距离,则甲方该冰壶得分,score_a 加 1。
    • 反之,如果乙方最小距离小于甲方,遍历乙方的冰壶距离,若满足条件则乙方该冰壶得分,score_b 加 1。
  3. 存储和更新总分

    • 将每局的得分 score_a 和 score_b 作为一个 std::pair 存储在 scores_per_round 向量中。
    • 同时更新甲乙双方的总得分 total_score_a 和 total_score_b
  4. 输出结果

    • 遍历 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;
}

代码解释:

  1. 输入处理

    • 首先读取规定的正整数 r,它是判断冰壶是否得分的距离限制。
    • 在循环中,每次读取甲方和乙方每一局 8 个冰壶距离目标点 P 的距离,分别存储在 distancesA 和 distancesB 向量中。
    • 如果读取甲方距离时第一个值为 -1,表示有一方弃权,结束比赛。
  2. 得分计算

    • 使用 std::min_element 函数分别找出甲方和乙方冰壶距离的最小值 minDistanceA 和 minDistanceB
    • 比较两个最小值,如果 minDistanceA < minDistanceB,遍历甲方的冰壶距离,若距离小于等于 r 且小于 minDistanceB,则甲方该冰壶得分,scoreA 加 1;反之,若 minDistanceB < minDistanceA,对乙方进行类似操作。
  3. 输出结果

    • 每局比赛结束后,输出该局甲乙双方的比分,格式为 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;
}

简化说明

  1. 命名空间使用:使用 using namespace std; 避免每次使用标准库组件时都写 std::,使代码更简洁。
  2. 变量命名简化:将 totalScoreA 简化为 totalAtotalScoreB 简化为 totalBdistancesA 简化为 adistancesB 简化为 b,减少代码长度。
  3. 循环结构:使用 for 循环替代 while 循环控制比赛局数,代码结构更紧凑。
  4. 输入输出简化:合并了部分输入输出代码,减少冗余。

代码解释

  1. 输入读取:读取规定的距离 r,后续每局读取甲方和乙方各 8 个冰壶距离,若甲方第一个输入为 -1 则停止比赛。
  2. 得分计算:找出双方冰壶最小距离,若甲方最小距离小,则遍历甲方冰壶距离计算得分;反之遍历乙方冰壶距离计算得分。
  3. 结果输出:每局输出该局比分,最后输出总比分。

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;
}

代码解释:

  1. 头文件与主函数
    • #include <iostream>:用于输入输出操作。
    • #include <vector>:用于使用 std::vector 容器存储冰壶距离。
    • #include <algorithm>:使用 std::min_element 函数找出最小距离。
    • int main():程序的入口函数。
  2. 变量定义与输入
    • int r, totalA = 0, totalB = 0;r 为规定的正整数,totalA 和 totalB 分别记录甲乙双方总得分,初始化为 0。
    • std::cin >> r;:读取输入的 r
  3. 比赛局数循环
    • for (int i = 0; i < 10; ++i):最多进行 10 局比赛。
  4. 每局数据处理
    • std::vector<int> a(8), b(8);:分别存储甲乙双方每局 8 个冰壶的距离。
    • 两个 for 循环分别读取甲乙双方冰壶距离。
    • if (a[0] == -1) break;:检查是否弃权,若弃权则结束比赛。
  5. 得分计算
    • int minA = *std::min_element(a.begin(), a.end()); 和 int minB = *std::min_element(b.begin(), b.end());:找出双方冰壶最小距离。
    • 根据最小距离比较结果,遍历相应方冰壶距离,若满足条件则得分加 1。
  6. 输出结果
    • 每局输出该局比分,格式为 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;
}

简化点说明

  1. 变量命名简化:将 totalA 简化为 tatotalB 简化为 tbminA 简化为 maminB 简化为 mbscoreA 简化为 sascoreB 简化为 sb,减少变量名长度,使代码更紧凑。
  2. 输入循环简化:使用范围 for 循环 for (int& x : a) 和 for (int& x : b) 替代传统的 for 循环来读取冰壶距离,代码更简洁。
  3. 输出换行符简化:将 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;
}

简化说明

  1. 变量命名:使用更简短的变量名,比如用 sa 和 sb 分别代表甲方和乙方的总得分,ca 和 cb 代表每局得分,ma 和 mb 代表每方冰壶的最小距离,减少代码的视觉负担。
  2. 循环使用:继续采用范围 for 循环来读取每方冰壶的距离,让代码更简洁。
  3. 标准库函数调用min_element 函数调用时省略了 std:: 前缀,因为当前代码的上下文里不会产生命名冲突,这样代码更简洁。
  4. 输出换行:保持使用 '\n' 进行换行,避免不必要的缓冲区刷新操作。

代码解释

  1. 输入与初始化:读取规定距离 r,并初始化甲乙双方总得分 sa 和 sb 为 0。
  2. 局数循环:通过 for 循环控制比赛局数,最多进行 10 局。
  3. 数据读取:使用范围 for 循环读取每局双方 8 个冰壶的距离。若甲方首个输入为 -1,则结束比赛。
  4. 得分计算:找出双方冰壶最小距离,根据比较结果遍历相应方冰壶距离,满足条件则该局得分加 1。
  5. 输出结果:每局输出该局比分,累加每局得分到总得分,最后输出双方总得分。

用最基础的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;
}

代码解释:

  1. 输入读取

    • 首先,程序读取一个整数 r,这是冰壶比赛中规定的得分距离限制。
    • 然后,使用嵌套的 for 循环来读取每一局双方各 8 个冰壶距离目标点 P 的距离。若甲方第一局第一个冰壶距离输入为 -1,则表示有一方弃权,比赛停止。
  2. 最小距离计算

    • 对于每一局,分别找出甲方和乙方 8 个冰壶距离目标点 P 的最小距离 minDistanceA 和 minDistanceB。这里使用简单的 for 循环遍历数组并比较元素大小来实现。
  3. 得分计算

    • 比较 minDistanceA 和 minDistanceB 的大小。如果甲方冰壶最小距离更小,遍历甲方冰壶距离数组,若某个冰壶距离小于等于 r 且小于乙方冰壶最小距离,则甲方此冰壶得分,scoreA 加 1;反之,若乙方冰壶最小距离更小,对乙方进行同样的操作。
  4. 输出结果

    • 每一局比赛结束后,输出该局甲乙双方的比分,格式为 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;
}

简化说明

  1. 头文件与命名空间:仅保留了必要的 <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;
}

缩短说明

  1. 变量命名:将变量名进一步缩短,如 totalA 变为 tAtotalB 变为 tBminA 变为 mAminB 变为 mBscoreA 变为 sAscoreB 变为 sB,减少字符数量。
  2. 初始化:将多个变量的声明和初始化合并在一行,减少代码行数。
  3. 弃权处理:在读取甲方数据时,如果发现 a[0] == -1,使用逗号表达式直接输出当前总得分并结束程序,简化了弃权逻辑的处理代码。
  4. 得分计算循环:将得分计算的 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 个冰壶距离目标点的距离,计算每局的得分并输出,最后输出双方的总得分。

代码详细解释

  1. 输入规定距离 r

    cpp

    int r;
    cin >> r;
    
     

    定义一个整数变量 r 用于存储规定的距离,通过 cin 从标准输入读取该值。

  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];
      

      分别定义两个长度为 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 数组中。
  5. 计算最小距离

    • 计算甲方冰壶最小距离

      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];
          }
      }
      

      同理,计算乙方冰壶的最小距离。
  6. 计算每局得分

    • 初始化每局得分

      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。
  7. 输出每局比分和累加总得分

    cpp

    cout << scoreA << ":" << scoreB << endl;
    totalScoreA = totalScoreA + scoreA;
    totalScoreB = totalScoreB + scoreB;
    
     

    输出这一局甲乙双方的比分,然后将这一局的得分累加到双方的总得分中。

  8. 输出最终总得分

    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 个冰壶离目标点的距离,看看哪一方的冰壶离得更近,符合条件的冰壶就能得分,最后算出双方的总得分。

详细解释

  1. 输入规定距离 r

    cpp

    int r;
    cout << "请输入规定的距离 r: ";
    cin >> r;
    
     

    先和小朋友说要输入一个规定的距离 r,然后用 cin 把小朋友输入的数字存到变量 r 里。

  2. 初始化总得分

    cpp

    int totalScoreA = 0;
    int totalScoreB = 0;
    
     

    甲方和乙方一开始都没有得分,所以总得分都设为 0。

  3. 比赛局数循环

    cpp

    for (int game = 1; game <= 10; game++) {
        // ...
    }
    
     

    用 for 循环来模拟比赛的局数,从第 1 局到第 10 局。每一局开始的时候,都会告诉小朋友现在是第几局。

  4. 每局比赛数据处理

    • 准备存储冰壶距离的 “盒子”

      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 这个 “盒子” 里。
  5. 计算最小距离

    • 找出甲方冰壶的最小距离

      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;
}

代码解释:

  1. 输入处理

    • 首先读取一个整数 r,它代表规定的得分距离限制。
    • 在每一局比赛中,先读取甲方的 8 个冰壶距离目标点 P 的距离,若第一个输入为 -1,则表示有一方弃权,比赛终止。接着读取乙方的 8 个冰壶距离。
  2. 最小距离计算

    • 对于甲方的 8 个冰壶距离,通过一系列的 if 语句比较找出最小距离 minA
    • 同样地,对于乙方的 8 个冰壶距离,找出最小距离 minB
  3. 得分计算

    • 比较 minA 和 minB 的大小。如果 minA < minB,说明甲方冰壶整体离目标点更近,然后依次检查甲方每个冰壶的距离是否小于等于 r 且小于 minB,若满足条件则甲方此冰壶得分,scoreA 加 1。
    • 若 minB < minA,则乙方冰壶整体离目标点更近,对乙方的冰壶进行类似的得分判断,scoreB 相应增加。
  4. 输出结果

    • 每一局比赛结束后,输出该局甲乙双方的比分,格式为 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;
}

代码解释

整体思路

这个程序模拟了冰壶比赛的计分过程,通过用户输入每局比赛双方冰壶距离目标点的距离,根据规则计算每局得分和总得分。

详细步骤

  1. 输入规定距离 r:程序会提示用户输入比赛规定的距离 r,并将其存储在变量 r 中。
  2. 初始化总得分:将甲方和乙方的总得分 totalScoreA 和 totalScoreB 初始化为 0。
  3. 比赛局数循环:使用 for 循环从第 1 局到第 10 局进行比赛模拟。每局开始时会提示当前是第几局。
  4. 输入冰壶距离:分别提示用户输入甲方和乙方 8 个冰壶离目标点 P 的距离。如果甲方第一个输入为 -1,则表示有一方弃权,比赛结束。
  5. 计算最小距离:分别找出甲方和乙方冰壶中离目标点 P 最近的距离 minA 和 minB
  6. 计算每局得分:比较 minA 和 minB 的大小,若 minA < minB,则计算甲方得分;若 minB < minA,则计算乙方得分。
  7. 输出每局比分:输出每一局甲乙双方的得分情况。
  8. 累加总得分:将每一局的得分累加到双方的总得分中。
  9. 输出最终总得分:比赛结束后,输出甲乙双方的最终总得分。

这样的代码风格更像是可达鸭在和你交流,用比较亲切、易懂的语言引导你完成整个冰壶比赛计分的过程,适合初学者理解。

在冰壶比赛中,给出一个目标点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}")

代码解释:

  1. 读取输入

    • 首先读取规定的距离 r
    • 然后通过循环最多进行 10 局比赛,每局比赛中读取甲方和乙方 8 个冰壶距离目标点 P 的距离。
    • 如果读取到只有一个整数 -1,则表示有一方弃权,停止比赛。
  2. 计算每局得分

    • 找出甲方和乙方冰壶的最小距离 min_distance_a 和 min_distance_b
    • 如果甲方冰壶的最小距离更小,遍历甲方的冰壶距离,若某个冰壶距离小于等于 r 且小于乙方冰壶的最小距离,则甲方此冰壶得分。
    • 同理,如果乙方冰壶的最小距离更小,遍历乙方的冰壶距离计算得分。
  3. 存储和输出结果

    • 每局比赛结束后,将本局的比分存储在 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;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值