题目描述:
古代某个狱卒某天闲着没事想和两个罪犯玩个游戏,他找了个国际象棋盘,每个格子放上一个硬币,硬币长得都一样,正反都是狱卒自己决定。
之后他只让A罪犯观看棋盘,并随便指一个硬币告诉A罪犯,只要B罪犯能选出这个硬币就释放A和B,之后A被允许选一个硬币翻面,然后A被带走了。接着B被带过来并被要求选一个硬币,如果他选到狱卒指的那个硬币就GE,反之GG。
A和B只能在游戏开始前进行策略交流,游戏中无法交流,在被带到棋盘前时他们也完全不知道棋盘上的硬币正反如何。
问:那么A和B怎么做才能有最大几率被释放呢?
前几天在朋友空间看到的题目,感觉挺有意思就拿过来分享讨论一下。
然而只给出了答案并没有解释答案的思路,答案见下。
(1)首先将棋盘分成下面6种样子(每个格子里面放着一枚硬币正反随意,并且编号为下图所示):
(2)然后在给号的棋盘上,对应着数数 。蓝色区域内的硬币个数为奇数时得到1,为偶数时得到0。这样我们就得到了一个六位数(每一张图都可以对应得到一个数字0或者1)上面六张图的顺序是从高位到低位。(A罪犯在观察棋盘的时候要做的首要工作就是将这个六位数按照上面的方式找出来)
(3)然后狱卒随心选择一个格子(这个格子里的硬币就是B罪犯需要翻转的,但是B罪犯并不知道),但是A罪犯知道是这个格子,也知道这个格子的编号(编号从0~63 )。每个格子都有唯一对应的一个六位二进制数,因为最大为111111正好为63 ,最小值为000000正好为0。(A罪犯接下来需要做的就是把狱卒所选格子的编号转化为一个六位的二进制数)
(4)A罪犯最后要求翻转一枚硬币来帮助同伴(B罪犯)找到狱卒所指的硬币。在前面A罪犯首先得到了一个六位数,也得到了狱卒选择格子对应的六位二进制数。最关键的一步:A罪犯需要将这两个数进行异或(相同得0,不同得1),得到了第三个六位二进制数。接下来A罪犯需要将这第三个六位二进制数转为十进制数。这个十进制数就是A罪犯要翻转的格子编号。
(5)A罪犯被带走了,B罪犯被带了过来。现在B罪犯面对着棋盘需要找到狱卒之前所选的硬币,好像无从下手啊。不过A罪犯是程序员给了B罪犯提示。只要按照上面六张图所示的找到现在棋盘对应的一个六位二进制数,然后把它转化为十进制数,这个十进制数就是我要翻转的格子的编号。
给一个棋盘的界面:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 |
48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
参考代码:
#include <bits/stdc++.h> using namespace std ; int main() { int a[8][8] ; srand(time(NULL)) ; memset( a , 0 ,sizeof ( a ) ) ; for( int i = 0 ; i < 8 ; i ++ ) { for( int j = 0 ; j < 8 ; j ++ ) { a[i][j] = rand()%2 ; } } cout<<"初始化界面为: \n"<<endl ; for( int i = 0 ; i < 8 ; i ++ ) { for( int j = 0 ; j < 8 ; j ++ ) { cout<<a[i][j]<<" " ; } cout<<endl ; } cout<<"- - - - - - - - - - - - - - - -\n"<<endl ; cout<<"原始六位数为: " ; int num[6] ; int bit0[6] ; memset( num , 0 , sizeof ( num ) ) ; memset( bit0 , 0 , sizeof ( bit0 ) ) ; int temp0[4]={ 1 , 3 , 5 , 7 } ; int temp1[4]={ 2 , 3 , 6 , 7 } ; int temp2[4]={ 4 , 5 , 6 , 7 } ; for( int i = 0 ; i < 4 ; i ++ ) { for( int j = 0 ; j < 8 ;j ++ ) { if( a[temp0[i]][j] == 0 ) num[3]++ ; if( a[temp1[i]][j] == 0) num[4]++ ; if( a[temp2[i]][j] == 0) num[5]++ ; if( a[j][temp0[i]] == 0) num[0]++ ; if( a[j][temp1[i]] == 0) num[1]++ ; if( a[j][temp2[i]] == 0) num[2]++ ; } } for( int i = 0 ; i < 6 ; i ++ ) { if( num[i]%2 == 0 ) bit0[i] = 0 ; else bit0[i] = 1 ; } for( int i = 5 ; i >= 0 ; i -- ) cout<<bit0[i]; cout<<endl ; int bitnum = 0 ; for( int i =0 ; i < 6 ; i ++ ) { int temp = bit0[i]*pow(2,i) ; bitnum += temp ; } cout<<"对应十进制数为: "<<bitnum<<endl<<"\n"; int row , col ; row = rand() % 8 ; col = rand() % 8 ; cout<<"轮到狱卒选择 :"<<endl ; cout<<"所选行为 "<<row<<" 所选列为"<<col<<endl<<"\n" ; int choose = 7 * row + col; cout<<"狱卒选择的硬币编号为: "<<choose<<endl<<"\n" ; int c1 = bitnum^choose ; cout<<"A罪犯得到的原始十进制数 异或 狱卒所选硬币的编号 得到: "<<c1<<endl<<"\n" ; int row1 = c1/8 ; int col1 = c1%8 ; cout<<"A罪犯应给为B罪犯翻转的硬币所在位置为:"; cout<<"行为:"<<row1<<" 列为:"<<col1<<endl<<"\n" ; if( a[row1][col1] == 1 ) a[row1][col1] = 0 ; else a[row1][col1] = 1 ; for( int i = 0 ; i < 8 ; i ++ ) { for( int j = 0 ; j < 8 ; j ++ ) { cout<<a[i][j]<<" " ; } cout<<endl ; } cout<<"- - - - - - - - - - - - - - - -\n"<<endl ; int bit1[6] ; memset( bit1 , 0 , sizeof ( 6 ) ) ; memset( num , 0 , sizeof ( num ) ) ; for( int i = 0 ; i < 4 ; i ++ ) { for( int j = 0 ; j < 8 ;j ++ ) { if( a[temp0[i]][j] == 0 ) num[3]++ ; if( a[temp1[i]][j] == 0 ) num[4]++ ; if( a[temp2[i]][j] == 0 ) num[5]++ ; if( a[j][temp0[i]] == 0) num[0]++ ; if( a[j][temp1[i]] == 0) num[1]++ ; if( a[j][temp2[i]] == 0) num[2]++ ; } } cout<<"B罪犯得到的六位二进制数为: " ; for( int i = 0 ; i < 6 ; i ++ ) { if( num[i]%2 == 0 ) bit1[i] = 0 ; else bit1[i] = 1 ; } for( int i = 5 ; i >= 0 ; i -- ) cout<<bit1[i] ; cout<<endl ; int bitnum1 = 0 ; for( int i =0 ;i < 6 ; i ++ ) { int temp = bit1[i] * pow ( 2 , i ) ; bitnum1 += temp ; } cout<<"B罪犯反转的硬币为: "<<bitnum1<<endl ; }
GCC运行结果:
求解释该方法的思路。O(∩_∩)O~