2014S_1:生活大爆炸版石头剪刀布

洛谷:P1328
OJ: I1328

代码分析:

  1. 变量初始化
    • n:表示进行的猜拳次数。
    • na:表示小 A 出拳周期的长度。
    • nb:表示小 B 出拳周期的长度。
    • ans1ans2:分别表示小 A 和小 B 的得分,初始为 0。
    • NA[205]NB[205]:分别存储小 A 和小 B 出拳的周期序列。
    • score[6][6]:表示不同手势之间的胜负关系,表中 score[i][j] 表示手势 i 与手势 j 的对战结果。
  2. 输入读取
    • 通过 cin 读取输入的 n, na, nb
    • 使用循环读取小 A 和小 B 的出拳序列 NANB,并存储到对应数组中。
  3. 主循环
    • 使用变量 ju 分别作为小 A 和小 B 出拳序列的索引,分别从 1 开始。
    • 循环 n 次,每一轮根据小 A 和小 B 的出拳来更新双方的得分:
      • ans1 累加 score[NA[j]][NB[u]],表示小 A 这轮的得分。
      • ans2 累加 score[NB[u]][NA[j]],表示小 B 这轮的得分。
    • 每轮之后,检查是否到达周期的末尾,如果到达,则索引重置到周期的开头,否则索引加 1。
  4. 结果输出
    • 最后输出 ans1ans2,分别表示小 A 和小 B 的总得分。

算法原理:

  • 该算法核心是通过两个循环周期的序列来模拟每一轮的猜拳结果,并根据预定义的胜负表来累计得分。每次模拟两人出拳后,根据出拳序列和周期的长度,使用循环处理出拳的轮换。时间复杂度为 O(N),因为每轮猜拳的得分计算和更新都是常数时间操作。

代码实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**************************************************************** 
 * Description:  2014年提高组第一题  生活大爆炸版石头剪刀布
 * Author: Alex Li
 * Date: 2024-10-11 10:50:06
 * LastEditTime: 2024-10-11 11:00:54
****************************************************************/
#include<iostream>  // 引入输入输出库
#include<cstdio>    // 引入标准输入输出函数库
#include<cstring>   // 引入字符串处理库
using namespace std;

int n;             // 表示进行的猜拳次数
int na, nb;        // na: 小A出拳的周期长度,nb: 小B出拳的周期长度
int ans1 = 0, ans2 = 0;  // ans1表示小A的得分,ans2表示小B的得分
int NA[205], NB[205];    // NA[]存储小A的出拳序列,NB[]存储小B的出拳序列

// 手势胜负关系表,score[i][j] 表示手势 i 对手势 j 的胜负关系
// 0表示平局,1表示i赢,-1表示i输
int score[6][6] = {
    {0, 0, 1, 1, 0},  // 剪刀 vs {剪刀, 石头, 布, 蜥蜴人, 斯波克}
    {1, 0, 0, 1, 0},  // 石头 vs {剪刀, 石头, 布, 蜥蜴人, 斯波克}
    {0, 1, 0, 0, 1},  // 布 vs {剪刀, 石头, 布, 蜥蜴人, 斯波克}
    {0, 0, 1, 0, 1},  // 蜥蜴人 vs {剪刀, 石头, 布, 蜥蜴人, 斯波克}
    {1, 1, 0, 0, 0}   // 斯波克 vs {剪刀, 石头, 布, 蜥蜴人, 斯波克}
};  

int main() {
    freopen("rps.in","r",stdin);
    freopen("rps.out","w",stdout);
    // 读取猜拳次数n、小A出拳周期na、小B出拳周期nb
    cin >> n >> na >> nb;

    // 读取小A的出拳规律
    for (int i = 1; i <= na; i++) 
        cin >> NA[i];

    // 读取小B的出拳规律
    for (int i = 1; i <= nb; i++) 
        cin >> NB[i];

    // j和u分别是小A和小B当前的出拳位置索引
    int j = 1, u = 1;

    // 模拟进行n次猜拳
    for (int i = 1; i <= n; i++) {    
        // 根据出拳结果更新双方的得分
        ans1 += score[NA[j]][NB[u]];  // 小A得分
        ans2 += score[NB[u]][NA[j]];  // 小B得分

        // 更新小A的出拳位置,若到了周期末尾则重置为1
        if (j == na) 
            j = 1;
        else 
            j++;

        // 更新小B的出拳位置,若到了周期末尾则重置为1
        if (u == nb) 
            u = 1;
        else 
            u++;
    }

    // 输出最终得分
    cout << ans1 << ' ' << ans2;
}
Scroll to Top