回 帖 发 新 帖 刷新版面

主题:[讨论]感激不尽啊,想了好久都想不出来

编写一个程序证明吉尔布雷德原理:拿出一副扑克牌,将大,小王去掉,使他们红黑相间,再把这副牌分成两叠,让每叠下面的那张牌颜色不同,接着把牌再洗在一起。然后,从洗过的牌底下逐对拿牌。这时,奇迹就会出现,不管原理如何洗牌,拿出的牌总是一红一黑

回复列表 (共1个回复)

沙发

说说我得一点思路吧:

假设有N张红黑相间的牌。N为偶数
a[0] = 0, a[1] = 1 ... a[N/2 - 1] = 0表示第一组牌
b[0] = 1, b[1] = 0 ... b[N/2 - 1] = 1表示第二组牌

先假设N = 8
则有0 1 , 0 1 和 1 0, 1 0这样的组合,显然通过插入组合能够取到所有0,1相间的序列(可以这么看,fa(0, 1) = (0, 1) fb(0, 1) = (1, 0)则通过fa 和fb一定能取得这样的序列),设这样的0 ,1相间的序列有 t 组;显然 t = 2 ^ (N / 2);
反证:假设洗牌后取牌时遇到拿出的两张牌是相同颜色,则可设 洗牌后得到的序列组合数 k > t
然后通过程序验证。
#include <stdio.h>
#define N 16
 
int main(int argc, char *argv[])
{
    int ct = 1; 
    int a[N / 2], b[N / 2], i, m, n; /*假设一个数组c[N]用以存储组合中的元素*/
    for(i = 0; i < N / 2; i++)
    {
        if(i % 2 == 0)
        {
            a[i] = 0;
            b[i] = 1;
        }
        else
        {
            a[i] = 1;
            b[i] = 0;
        }
    }
    
    for(m = n = 0; m < N/2 && n < N/2; )
    {
        if(a[m] ^ b[n])
        {
            m++;
            ct = ct << 1 ;        /*此时有两种情况,要么c[i] = a[m] = 0(或1),要么c[i] = b[n] = 1 (或1)*/        
        }                        /*由于算法不能存在二义性,故而只通过记数来记录操作,操作是简单认为m ++,即只考虑c[i] = a[m]的情况,这里是关键*/
        else
        {
            n++;                /*如果两者相等,则c[i]只取0或1*/
        }                        /*事实上选取m++和n++并不影响,只要有一个满足 < N / 2即可*/
    } 
    printf("ct = %d\n", ct);
    return 0;
}

得到的ct == 2 ^ (N/2),说明无多余解的,与假设洗牌后取牌时遇到拿出的两张牌是相同颜色 矛盾的。

------------------------
不知道考虑情况是否准确。仅供参考。。

我来回复

您尚未登录,请登录后再回复。点此登录或注册