PATPAT乙级

PAT-B1018-锤子剪刀布(C语言实现)

2020-03-10  本文已影响0人  青木书生123

题目要求

大家应该都会玩“锤子剪刀布”的游戏:两人同时给出手势,胜负规则如图所示:

剪刀石头布

现给出两人的交锋记录,请统计双方的胜、平、负次数,并且给出双方分别出什么手势的胜算最大。

输入格式

输入第 1 行给出正整数 N(≤10^5),即双方交锋的次数。随后 N 行,每行给出一次交锋的信息,即甲、乙双方同时给出的的手势。C代表“锤子”、J 代表“剪刀”、B 代表“布”,第 1 个字母代表甲方,第 2 个代表乙方,中间有 1 个空格。

输出格式

输出第 1、2 行分别给出甲、乙的胜、平、负次数,数字间以 1 个空格分隔。第 3 行给出两个字母,分别代表甲、乙获胜次数最多的手势,中间有 1 个空格。如果解不唯一,则输出按字母序最小的解。

输入样例

10
C J
J B
C B
B B
B C
C C
C B
J B
B C
J J

输出样例

5 3 2
2 3 5
B B

分析

1. 寻找思路(按先处理,再分析输入和输出的顺序)

根据题目要求处理过程可以分为两个模块:

  1. 比较模块,比出甲乙两人的胜负
  2. 记录成绩模块,分别记录两人的胜负,以及出BCJ中的哪一个取胜的

显而易见,对数据的处理过程就是这两个模块反复执行的过程

对输入分析,要承载输入的数据那么需要一个int类型的N,以及两个100000大小的char数组分别保存甲乙两人每次对决的数据

对输出进行分析,首先是甲乙的胜平负次数以及获胜次数最多的手势,这个可以用变量来存储,也可以用数组来存储,我当时是用的数组,因为感觉太多变量不太好,但想想数组的实质其实就是一堆变量的集合,只不过在它们身上额外定义了一种线性关系而已,用数组和用变量都差不多的。另外,对于输出格式有要求,这说明要有一个输出格式的控制模块,最后一句如果解不唯一,则输出按字母序最小的解。说明输出时要有一个嵌套的if条件,不过我之后用数组对BCJ三个字母做了转换处理,可以避免这个嵌套的if条件句

2. 细节实现

有了一个大致的思路和框架,接下来就是各个模块的细节问题了,为了方便直接给甲乙起名叫杰瑞和汤姆,把BCJ分别转化为数字123,这样就有了天然的大小关系,小的胜大的输,只有一种情况是例外,那就是1和3放在一起比的时候,所以要加一个判断结构,把BCJ转化成数字还有一个好处,那就是直接用数组存储BCJ分别的获胜次数,用相应的数组下标来标记BCJ(下标012比123相对应少1),这样处理直接用一个temp变量从数组第一个开始比较,保存下第一个的值,只有当遇到比temp大的值时才改变temp的值,这样选出来的最大值一定是值最大且字母最小的(因为数组是按字母排序),输出时按下标对应的字母输出即可。

所以,要加一个转化模块

可以关门放代码了

#include<stdio.h>
#define MAXSIZE 100000
int inverse(char);  //转换模块
int compare(int,int);   //比较模块
void output(int *);     //对输出格式进行控制
void victory_max(int *);    //找出获胜次数最多的那个字母
int main(){
    int N;
    int Jerry_choice[3]={0},Tom_choice[3]={0};  //BCJ获胜的次数
    int Jerry_scores[3]={0},Tom_scores[3]={0};  //胜平负次数
    int Jerry[MAXSIZE],Tom[MAXSIZE];    //两人的比赛记录
    int result;     //比较出来的结果
    char temp_J,temp_T;     //暂存BCJ以把它转换成数字

    scanf("%d",&N);
    for(int i=0;i<N;i++){
        getchar();  //吃掉‘\n’,容易忽略
        scanf("%c %c",&temp_J,&temp_T);
        Jerry[i]=inverse(temp_J);
        Tom[i]=inverse(temp_T);
    }
    for(int i=0;i<N;i++){
        result=compare(Jerry[i],Tom[i]);
        if(result==0){
            Tom_scores[0]++;
            Jerry_scores[2]++;
            Tom_choice[Tom[i]-1]++;     //别忘了-1,因为数组从0开始
        }
        else if(result==1){
            Jerry_scores[0]++;
            Tom_scores[2]++;
            Jerry_choice[Jerry[i]-1]++;
        }
        else{
            Jerry_scores[1]++;
            Tom_scores[1]++;
        }
    }
    output(Jerry_scores);
    printf("\n");
    output(Tom_scores);
    printf("\n");
    victory_max(Jerry_choice);
    printf(" ");
    victory_max(Tom_choice);
    return 0;
}
int inverse(char x){
    if(x=='B'){
        return 1;
    }
    if(x=='C'){
        return 2;
    }
    if(x=='J'){
        return 3;
    }
}
int compare(int Jerry,int Tom){     //Jerry赢返回1,Tom赢返回0,平返回2;
    if(Jerry>Tom){
        if(Jerry==3 && Tom==1){     //Tom是布,Jerry是剪刀
            return 1;
        }
        return 0;
    }
    if(Jerry<Tom){
        if(Tom==3 && Jerry==1){
            return 0;
        }
        return 1;
    }
    else{
        return 2;
    }
}
void output(int *p){
    for(int i=0;i<3;i++){
        printf("%d",p[i]);
        if(i!=2){
            printf(" ");
        }
    }
}
void victory_max(int *p){
    int temp=-1,k;

    for(int i=0;i<3;i++){
        if(temp<p[i]){
            temp=p[i];
            k=i;
        }
    }
    if(k==0){
        printf("B");
    }
    if(k==1){
        printf("C");
    }
    if(k==2){
        printf("J");
    }
}

写在后面

因为第二次调用scanf()时,用的是%c,所以scanf()不会忽略之前输入N时以及每个循环结束时附带的'\n',所以要用getchar()消掉'\n'这个字符

关于消掉‘\n’还有一种方法:

int recovery;   //回收

    for(int i=0;i<N;i++){
        scanf("%c %c %c",&recovery,&temp_J,&temp_T);
        Jerry[i]=inverse(temp_J);
        Tom[i]=inverse(temp_T);
    }

建立一个变量,这样可以让scanf()读入三个字符,第一个,即‘\n’,赋值给该变量,这样也可以使‘\n’不产生影响

有什么问题或文章疏漏的地方可以在下面评论中指出,也可以进入主页关注我的微信公众号

上一篇下一篇

猜你喜欢

热点阅读