主题:[讨论]感激不尽啊,想了好久都想不出来
xueshaopeng
[专家分:0] 发布于 2011-05-20 23:32:00
编写一个程序证明吉尔布雷德原理:拿出一副扑克牌,将大,小王去掉,使他们红黑相间,再把这副牌分成两叠,让每叠下面的那张牌颜色不同,接着把牌再洗在一起。然后,从洗过的牌底下逐对拿牌。这时,奇迹就会出现,不管原理如何洗牌,拿出的牌总是一红一黑
回复列表 (共1个回复)
沙发
fragileeye [专家分:1990] 发布于 2011-05-21 13:34:00
说说我得一点思路吧:
假设有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),说明无多余解的,与假设洗牌后取牌时遇到拿出的两张牌是相同颜色 矛盾的。
------------------------
不知道考虑情况是否准确。仅供参考。。
我来回复