石头剪刀布 -2013编程之美全国测试赛 每日一练
Description:石头剪刀布是常见的猜拳游戏。石头胜剪刀,剪刀胜布,布胜石头。如果两个人出拳一样,则不分胜负。
一天,小A和小B正好在玩石头剪刀布。已知他们的出拳都是有规律的,比如:“石头-布-石头-剪刀-石头-布-石头-剪刀……”,就是以“石头-布-石头-剪刀”为周期的。请问,小A和小B比了N轮之后,谁赢了?
Input:
输入的第一行包含一个整数K,表示K组测试数据。
之后的每组测试数据包含三行。第一行包含三个整数:N,NA,NB,分别表示比了N轮,小A出拳的周期长度,小B出拳的周期长度。第二行包含NA个整数,表示小A出拳的规律,第三行包含NB个整数,表示小B出拳的规律。其中,0表示“石头”,2表示“剪刀”,5表示“布”。
对于小数据,0 < K,N,NA,NB <= 10;对于大数据,0 < K,N,NA,NB <= 100;
Output:
对于每组测试数据,输出一行。如果小A赢了,输出A;如果小B赢了,输出B;如果两人打平,输出draw。
Sample Input
2 10 3 4 0 2 5 0 5 0 2 5 3 3 2 0 5 0 2 5 |
Sample Output
A draw |
Hint:
对于第一组测试数据,猜拳过程为: A:0 2 5 0 2 5 0 2 5 0 B:0 5 0 2 0 5 0 2 0 5 所以A赢了4轮,B赢了2轮,双方打平4轮,所以A赢了。 对于第二组测试数据,猜拳过程为: A:2 0 5 2 0 B:0 2 5 0 2 所以A赢了2轮,B赢了2轮,双方打平1轮,所以最终打平了。 |
思路:假设A出拳的周期长度为na,B出拳的周期长度为nb,对于具体的出拳规律则使用两个数组arrayA[],arrayB[]来保存。
在第i次出拳时,判断获胜方的方法:比较A出arrayA[i%na]、B出 arrayB[i%nb]的赢家,统计n次出拳后A总共赢的次数和B总共赢的次数,然后按要求输出即可。
优化方法:在以上方法中,总是需要比较n次才能算出赢家,这样在n比较大时可能存在着周期性的重复比较。如n = 40, na = 3,nb =4时,显然n从13到36的比较就很多余了,所以考虑优化这些多余的比较——聪明如你,肯定想到可以使用na和nb的最小公倍数来进行优化了吧~
此外,思考具体的计算过程是否是将最小公倍数周期内的比较同不满足整个周期(第37-40次)的比较相加?(PS:之所以将此项单独列出,是因为在同学的讨论中确实存在这样的误解,所以看仔细了哦~)
试想在前12次比较中B先赢4次,然后在5-12次中A、B平局2次、A赢6次,然后再第37-40次B赢4次,A总共赢6次,B总共赢8次,最终B取得胜利?
也许你会大声的说No!在前36次中A共赢18次,B共赢12次;在全40次的比较中A赢18次,B赢16次,结果是A赢。
下面上代码:
1 #include<iostream> 2 using namespace std; 3 static int winA; 4 static int winB; 5 //求正整数a和b的最大公约数 6 int divisor(int a, int b){ 7 int n = a>b ? a:b; 8 if(a>b) a = b; 9 else return a; 10 while(n%a !=0){ 11 b = a; 12 a = n%a; 13 n = b; 14 } 15 return a; 16 } 17 18 //求正整数a和b的最小公倍数 19 int multiple(int a, int b){ 20 return a/divisor(a,b)*b; 21 } 22 23 void cmp(int arrayA[],int na, int arrayB[], int nb,const int cal) 24 { 25 for(int i=0; i<cal; i++) 26 { 27 int a = i % na; 28 int b = i % nb; 29 //A赢 30 if((arrayA[a]==0 && arrayB[b]==2)||(arrayA[a]==2 && arrayB[b]==5)||(arrayA[a]==5 && arrayB[b]==0)) 31 { 32 winA++; 33 }else if(arrayA[a] != arrayB[b]) 34 {//B赢 35 winB++; 36 } 37 } 38 } 39 40 int main() 41 { 42 int K, N, NA, NB, cal, i; 43 cin>>K; 44 while(K>0){ 45 winA=0, winB=0; 46 cin>>N>>NA>>NB; 47 int* arrayA = (int *)malloc((NA+1)*sizeof(int)); 48 int* arrayB = (int *)malloc((NB+1)*sizeof(int)); 49 for(i=0; i<NA; i++) 50 { 51 cin>>arrayA[i]; 52 } 53 for(i=0; i<NB; i++) 54 { 55 cin>>arrayB[i]; 56 } 57 //通过最小公约数来实现最少的比较次数 58 cal = multiple(NA,NB); 59 if(N <= cal) 60 cmp(arrayA,NA,arrayB,NB,N); 61 else 62 { 63 cmp(arrayA,NA,arrayB,NB,cal); 64 int mod = N % cal, mul = N / cal; 65 winA *= mul; 66 winB *= mul; 67 if(mod) 68 cmp(arrayA,NB,arrayB,NB,mod); 69 } 70 //输出计算结果 71 if(winA==winB) 72 cout<<"draw"<<endl; 73 else if(winA>winB) 74 cout<<"A"<<endl; 75 else 76 cout<<"B"<<endl; 77 //别忘了释放空间 78 free(arrayA); 79 free(arrayB); 80 K--; 81 } 82 return 0; 83 }