PAT-B1018-锤子剪刀布(C语言实现)
题目要求
剪刀石头布大家应该都会玩“锤子剪刀布”的游戏:两人同时给出手势,胜负规则如图所示:
现给出两人的交锋记录,请统计双方的胜、平、负次数,并且给出双方分别出什么手势的胜算最大。
输入格式
输入第 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. 寻找思路(按先处理,再分析输入和输出的顺序)
根据题目要求处理过程可以分为两个模块:
- 比较模块,比出甲乙两人的胜负
- 记录成绩模块,分别记录两人的胜负,以及出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’
不产生影响
有什么问题或文章疏漏的地方可以在下面评论中指出,也可以进入主页关注我的微信公众号