作者的话:若有朋友复制代码去PAT试着运行遇到问题的:
1.可能是格式问题,可以先把从本站复制的代码粘贴到记事本,再把记事本里的代码复制,然后粘贴到PAT的代码区,提交本题回答,应该就可以了;
2.可能是注释原因,PAT有时候检测到注释会编译错误,所以可以先把注释删了,再进行提交回答。
3.可能是作者当初根据题目写出来的代码仍存在一些疏漏,而恰好当时的测试机制没那么完善,没检测出问题。后面测试机制有所更新,故出现问题,若有相关需要的可以评论区留言或私信作者,我看到的话会去再查一下疏漏之处,然后更新文章。
一、题目描述
大家应该都会玩“锤子剪刀布”的游戏:两人同时给出手势,胜负规则:锤子>剪刀,剪刀>布,布>锤子。
现给出两人的交锋记录,请统计双方的胜、平、负次数,并且给出双方分别出什么手势的胜算最大。
输入格式:
输入第 1 行给出正整数 N(≤105),即双方交锋的次数。随后 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
二、解题思路
读题:
两个人玩石头剪刀布,程序先接收游戏回合数N,然后接收N回合两人各自给出的手势(C代表“锤子”、J 代表“剪刀”、B 代表“布”,第 1 个字母代表甲方,第 2 个代表乙方,中间有 1 个空格)。程序对这些数据进行统计和处理,最后分别用一行输出甲、乙的胜、平、负次数,数字间加空格。并在第三行输出甲乙两人获胜次数最多的手势,最多获胜手势不唯一时输出字母序最小的手势。
思路:
1.定义需要的变量(实际解题时是先定义认为需要用到的变量,后面遇到问题需要新定义变量时再回到上头来定义新的变量),从键盘接收N存入变量n中;
2.设置循环,循环N轮,每一轮循环对应游戏的一个回合,分析谁胜谁负,用变量count记录甲的胜、平、负次数(最后也能凭借甲的胜负记录知道乙的胜负记录,故不需要重复记录),同时在胜利情况下记录甲用的各种手势的次数和失败情况下甲用的手势的次数(甲失败时的手势次数可以推导出出乙胜利的各种手势次数);
3.输出相应内容。
三、具体实现
0.标准C源程序框架
#include <stdio.h>
int main()
{
return 0;
}
1.定义需要的变量(实际解题时是先定义认为需要用到的变量,后面遇到问题需要新定义变量时再回到上头来定义新的变量),从键盘接收N存入变量n中;
int n;//接收游戏的回合数
int i = 0;//循环变量,用于接收双方手势和统计胜负次数的循环
int count[3] = { 0 };//[0]-胜 [1]-平 [2]-负
char x, y;//用于存储代表双方手势的字符
int result = 0;//用于条件判断,判断是胜利、平局还是失败
int c[2] = { 0 }, j[2] = { 0 }, b[2] = { 0 };//[0]存储甲用三某种势胜利的次数,[1]存储甲用某种手势失败的次数
scanf("%d", &n);
2.设置循环,循环N轮,每一轮循环对应游戏的一个回合,分析谁胜谁负,用变量count记录甲的胜、负、平次数(最后也能凭借甲的胜负记录知道乙的胜负记录,故不需要重复记录),同时在胜利情况下记录甲用的各种手势的次数和失败情况下甲用的手势的次数(甲失败时的手势次数可以推导出出乙胜利的各种手势次数);
for (i = 0; i < n; i++)
{
getchar();//每次接收数据时,回车字符会留在输入缓冲区,不拿掉的话会对下一轮循环接收字符产生干扰
scanf("%c %c", &x, &y);//b,c,j
result = x - y;
if (result==0)//平局情况——字符相减为0
{
count[1]++;
}
else if ((result==-1)||(result==-7)||(result==8))//胜利情况——1.B-C 2.C-J 3.J-B
{
count[0]++;//甲胜场+1
if (x == 'B') b[0]++;//甲拿什么赢的,相应变量+1
else if (x == 'C') c[0]++;
else j[0]++;
}
else//失败情况
{
count[2]++;
if (x == 'B') j[1]++;//甲拿什么输的,相应的克制变量+1
else if (x == 'C') b[1]++;
else c[1]++;
}
}
3.输出相应内容。
printf("%d %d %d\n", count[0], count[1], count[2]);//甲的胜平负
printf("%d %d %d\n", count[2], count[1], count[0]);//乙的胜平负(胜、负次数其实就是甲的胜、负次数换一下)
if ((b[0] >= c[0]) && (b[0] >= j[0]))//b次数大于另外两个时,输出"B ",等于情况B序号最小也是一样的输出
{
printf("B ");
}
else if ((c[0] >= b[0]) && (c[0] >= j[0]))
{
printf("C ");
}
else
{
printf("J ");
}
if ((b[1] >= c[1]) && (b[1] >= j[1]))
{
printf("B");
}
else if ((c[1] >= b[1]) && (c[1] >= j[1]))
{
printf("C");
}
else
{
printf("J");
}
四、全部代码
#include <stdio.h>
int main()
{
int n;//接收游戏的回合数
int i = 0;//循环变量,用于接收双方手势和统计胜负次数的循环
int count[3] = { 0 };//[0]-胜 [1]-平 [2]-负
char x, y;//用于存储代表双方手势的字符
int result = 0;//用于条件判断,判断是胜利、平局还是失败
int c[2] = { 0 }, j[2] = { 0 }, b[2] = { 0 };//[0]存储甲用三某种势胜利的次数,[1]存储甲用某种手势失败的次数
scanf("%d", &n);
for (i = 0; i < n; i++)
{
getchar();//每次接收数据时,回车字符会留在输入缓冲区,不拿掉的话会对下一轮循环接收字符产生干扰
scanf("%c %c", &x, &y);//b,c,j
result = x - y;
if (result==0)//平局情况——字符相减为0
{
count[1]++;
}
else if ((result==-1)||(result==-7)||(result==8))//胜利情况——1.B-C 2.C-J 3.J-B
{
count[0]++;//甲胜场+1
if (x == 'B') b[0]++;//甲拿什么赢的,相应变量+1
else if (x == 'C') c[0]++;
else j[0]++;
}
else//失败情况
{
count[2]++;
if (x == 'B') j[1]++;//甲拿什么输的,相应的克制变量+1
else if (x == 'C') b[1]++;
else c[1]++;
}
}
printf("%d %d %d\n", count[0], count[1], count[2]);//甲的胜平负
printf("%d %d %d\n", count[2], count[1], count[0]);//乙的胜平负(胜、负次数其实就是甲的胜、负次数换一下)
if ((b[0] >= c[0]) && (b[0] >= j[0]))//b次数大于另外两个时,输出"B ",等于情况B序号最小也是一样的输出
{
printf("B ");
}
else if ((c[0] >= b[0]) && (c[0] >= j[0]))
{
printf("C ");
}
else
{
printf("J ");
}
if ((b[1] >= c[1]) && (b[1] >= j[1]))
{
printf("B");
}
else if ((c[1] >= b[1]) && (c[1] >= j[1]))
{
printf("C");
}
else
{
printf("J");
}
return 0;
}
五、另一种思路
本来想优化一下,减少运行时间的,结果搞出这一种方法比上一种花费了更多的运行时间。有懂算法的朋友讲解一下这是为什么吗?我本来还以为第二种会减少运算次数,会运行更快的。
#include <stdio.h>
int main()
{//x y胜平负次数,胜场最多手势
int n;//接收游戏的回合数
int i = 0;//循环变量,用于接收双方手势和统计胜负次数的循环
char x, y;
int a[3] = { 0 }, b[3] = {0};//记录甲、乙胜利时各自用的三种手势的次数
int result[2] = { 0 };//记录双方胜场
scanf("%d",&n);
for (i = 0; i < n; i++)
{
getchar();//吸收回车
scanf("%c %c",&x,&y);
switch(x-y)
{
case -7://锤子C>剪刀J
{ a[0]++; break;}//a[0][0]-甲用锤子胜利的次数
case 8://剪刀J>布B
{ a[1]++; break;}//a[0][1]-甲用剪刀胜利的次数
case -1://布B>锤子C
{ a[2]++; break;}//a[0][2]-甲用布胜利的次数
case 7://剪刀J<锤子C
{ b[0]++; break;}//a[1][0]-乙用锤子胜利的次数
case -8://布B<剪刀J
{ b[1]++; break;}//a[1][1]-乙用剪刀胜利的次数
case 1://锤子C<布B
{ b[2]++; break;}//a[1][2]-乙用布胜利的次数
}
}
result[0] = a[0] + a[1] + a[2];//甲的胜场数
result[1] = b[0] + b[1] + b[2];//乙的胜场数
printf("%d %d %d\n",result[0],n-result[0]-result[1],result[1]);//输出甲的胜平负
printf("%d %d %d\n",result[1],n-result[0]-result[1],result[0]);//输出乙的胜平负
x = a[1] > (a[2] >= a[0] ? a[2] : a[0]) ? 'J' : (a[2] >= a[0] ? 'B' : 'C');
y = b[1] > (b[2] >= b[0] ? b[2] : b[0]) ? 'J' : (b[2] >= b[0] ? 'B' : 'C');
printf("%c %c", x, y);
return 0;
}