1018 锤子剪刀布 (20 分)

1018 锤子剪刀布 (20 分)

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

FigCJB.jpg

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

输入格式:

输入第 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

思路

  • 考虑到最后要输出字典序的最小的解,将三种手势按字典序排序,即B(布)、C(石头)、J(剪刀)。可以发现,这个顺序又恰好是循环相克的顺序,即B胜C,C胜J,J胜B,将BCJ对应位0、1、2,作为一维数组mp的三个元素,mp[0]='B'、mp[1]='C'、mp[2]='J';同时写一个函数change(char c)来将手势对应到数字

  • 对每组读入的甲乙手势c1和c2,先将其通过change函数准换为数字k1和k2,然后判断该局输赢。由于设置的顺序恰好就是循环相克顺序,因此k1胜k2的条件是(k1+1)%3k2,而k1和k2平的条件是k1k2;k2胜k1的条件是(k2+1)%3 ==k1

    在得到该局的输赢之后,对甲乙的胜、平、负次数进行操作,并对赢得该局的一方的手势次数加一

  • 比较得到胜利次数最多的手势,输出需要的信息

  • 注意点:

    1. 由于scanf使用%c时会将换行符\n读入,因此需要在合适的地方用getchar吸收空格,否则会导致读入与题意不符。
    2. 甲赢的时候同时要记乙负,乙赢甲负,这是成对出现的。

参考代码

#include<stdio.h>

int change(char c){//字符转变数字的方法,定义个int类型的返回函数
	if(c == 'B') return 0;
	if(c == 'C') return 1;
	if(c == 'J') return 2; 
} 

int main(){
	int n;
	char mp[3] = {'B', 'C', 'J'};//字符与0, 1, 2一一对应
	scanf("%d", &n);
	char c1, c2;
	int k1, k2;
	int hand_A[3] = {0}, hand_B[3] = {0};
	int v1 = 0, v2 = 0, f1 = 0, f2 = 0, p = 0;
	for(int i = 0; i < n; i++){
		getchar();
		scanf("%c %c", &c1, &c2);
		k1 = change(c1);//转换为数字 
		k2 = change(c2);
		if((k1 + 1) % 3 == k2){
			v1++;//这里的v1v2其实都可以用数组来记录,会更加方便,f1和f2同理
			f2++;
			hand_A[k1]++;
		}else if(k1 == k2){
			p++;
		}else{
			v2++;
			f1++;
			hand_B[k2]++;
		}
	}	
	printf("%d %d %d\n", v1, p, f1);
	printf("%d %d %d\n", v2, p, f2);
	int id1 = 0, id2 = 0;
	for(int i = 0; i < 3; i++){
		if(hand_A[i] > hand_A[id1]) id1 = i;//id1表示最大的手势,如果有比他大的,就更像id1
		if(hand_B[i] > hand_B[id2]) id2 = i; //这里就算有多个解,但是i是从小到大的,当不等式两把相等的时候,并不会进行后面的句子,所以还是可以去到最小的解
	}
	
	printf("%c %c\n", mp[id1], mp[id2]); //转变回BCJ
	return 0; 
}
posted @ 2021-07-20 09:00  shiff  阅读(75)  评论(0编辑  收藏  举报