Impossible escape

来源:互联网 发布:oracle数据库中文注释 编辑:程序博客网 时间:2024/06/01 21:27

一个数学问题

  • 一个看守跟两个囚徒玩一个游戏。游戏开始前两个囚徒可以商量策略(两位囚徒均熟悉游戏流程),游戏开始后,两个囚徒再也不能相见。看守在一个8×8的棋盘摆了64个硬币,硬币有正面,有反面,是随机的。看守叫来A,明确告诉囚徒A哪一枚硬币下面藏着一张纸。而后,他要求A选择翻转棋盘中的一枚硬币。注意:这个翻转硬币是必须的,而且只能是一枚(除了翻一枚硬币以外,A不允许再有多余的动作)。之后,他让A离开。叫来B,如果B可以指出哪个硬币下藏着这张纸,A和B都可以释放,不然A和B都被绞死。

  • 问:A和B商量哪种策略可以使得两人存活的概率最高?(其实是100%存活)

解法(解法来自知乎: 杨帆)

  • 把64个格子按照0~63的顺序编好号。记第i个格子的硬币状态为ai,正面朝上记0,反面朝上记1.对于每一个棋盘的局面{ai},定义函数f({ai})=0 xor k1 xor k2 … xor km,其中aki=1,i=1…m。 即把棋盘上所有向下的硬币的坐标给异或运算,如果全朝上那就是0.
  • 囚犯A:

    • 看了任一棋盘局面{ai}后,计算出f({ai}),然后假设纸所在的位置坐标为j, 计算出的值l = j xor f({ai}),然后翻转坐标为l的硬币即可。
  • 囚犯B:

    • 直接计算新局面{ai}’对应的f({ai})’, 即为纸条的坐标j。原因:由于新局面{ai}’是局面{ai}翻转坐标为l的硬币得到的,所以显然有:f({ai})’ = f({ai}) xor l. 又有:l = j xor f({ai}),从而有由此f({ai})’ = f({ai}) xor l = f({ai})’ = f({ai}) xor j xor f({ai}) = j,B能够以100%正确率指出纸条的位置。
  • 简单的说就是:

    • A和B商量好计算正面朝上所有坐标相互异或的值还是正面朝下
    • 商量好后, A计算出当前局面的值,然后翻转坐标为l的硬币
    • B计算出自己当前局面的值就是正确的位置

模拟代码

测试样例:

Impossible escape_Input.txt

34U U D D D U U UU U U D D D U UD D D U U U U UD U U U U D U UD D U D U U D UU D U D U U U UU U D D D U U DU U D D D U U D50U D U U U D D UD U U U U U U UU D D U U D U DU D D D U D U UU U U D U U D DU U U U D D U DU D D U D U D UD D U D D D D U40D D U D U D D DD D D D U D D UD D D U D D D UU U U D U D U DD U U U D D D DD U U U D D D UD D U D U U D DU D D D U D U D

测试代码:

Impossible escape.cpp

#include <iostream>using namespace std;const int SIZE = 64;bool box[SIZE];       // 棋盘64格, 0表示正面朝上,1表示正面朝下int main(int argc, char const *argv[]){    char tmp;    int fa, fb, l;    int RightPos;    freopen("Impossible escape_Input.txt", "r", stdin);    while (~scanf("%d", &RightPos))    {        for (int i = 0; i < SIZE; ++i)        {            scanf("%c", &tmp);            getchar();            // 0表示正面朝上, 1 表示正面朝下            if('D' == tmp) box[i] = 1;            else if('U' == tmp) box[i] = 0;        }        // ====================================        // 模拟囚犯A拿到局面{ai}        fa = 0;        for (int i = 0; i < SIZE; ++i)        {            if(box[i]) fa ^= i;        }        l = fa^RightPos;        // 计算A应该翻转硬币的坐标        box[l] ^= 1;            // 翻转硬币        // ====================================        // 模拟囚犯B拿到局面{ai}'        fb = 0;        for (int i = 0; i < SIZE; ++i)        {            if(box[i]) fb ^= i;        }        printf("%d\n", fb);     // 输出B认为有纸片的目标位置    }    return 0;}

生成测试样例代码:

Impossible escape_Createinput.cpp

// 用于生成测试样例// U表示硬币正面朝上, D表示硬币正面朝下#include <iostream>#include <time.h>#include <cstdlib>using namespace std;const char data[2] = {'D', 'U'};int main(int argc, char const *argv[]){    freopen("Impossible escape_Input.txt", "w", stdout);    int test_num;    srand(time(NULL));    scanf("%d", &test_num);    for (int i = 0; i < test_num; ++i)    {        printf("%d\n", rand()%64);        for (int i = 0; i < 8; ++i)        {            for (int j = 0; j < 8; ++j)            {                printf("%c", data[rand()%2]);                if(j != 7) printf(" ");                else printf("\n");            }        }        printf("\n");    }    return 0;}
原创粉丝点击