魔术师发牌
舞台上:魔术师利用一副牌中的13张黑桃牌(其实神马花色都行),预先给他们排好后叠在一起,肯定是有固定的顺序,牌面朝下面,对观众们说“我不看牌,只需要数一数就可以猜到每张牌是什么~。”
然后呢,魔术师讲最上面的那张牌数为1 ,把它翻过来正好是黑桃A,将黑桃A放在桌子上,第二次数1,2,将第一张牌放在这些牌的下面,将第二张牌翻过来 正好是黑桃2 ,也将它放在 桌子上 ,这样,依次进行下去,13张牌被全部翻出,而且 准确无误。
实际上是这样的。一开始,把有序叠好的牌放在桌面上铺好 一列, 最上面的那张为 黑桃A 也就是 1,然后把它拿出来,扔掉 ,然后从上边取出1张牌放到最底下,打开第二张牌是黑桃2,扔掉;再依次将2张放到底下,第三张是黑桃3,扔掉;依次。。。。。知道最后剩一张牌,黑桃K。
先不要纠结魔术师如何洗牌,洗成固定顺序,咱们先看看是那种顺序能够实现这种神奇的发牌方式。
解决方案:
利用循环链表,初始化13个0的循环链表,第一个为1,然后走两步为2,再走三步为3,再走四步为4,到第五步的时候就出现问题了,已经循环到头部了,这时我们定个规则,如果步过的节点不为0,则跳过,直到0为止。说白了,就是步过的数量,必须是步过0的数量。
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int data;
struct node* next;
}node;
node* ghead = NULL;
//创建没有头节点的循环链表
void create_list(int num)
{
node* ltail = NULL, * lnew = NULL;
int i;
/*ghead = (node*)malloc(sizeof(node));
ltail = ghead;*/
for (i = 0; i < num; i++)
{
lnew = (node*)malloc(sizeof(node));
lnew->data = 0;
if (i == 0)
{
ghead = lnew;
lnew->next = lnew;
}
else
{
lnew->next = ltail->next;
ltail->next = lnew;
}
ltail = lnew;
}
}
void printlist(node* ll)
{
node* llh = NULL;
llh = ll;
int i = 1;
if (!ll)
{
printf("链表为空");
return;
}
while (ll->next != llh)
{
printf("%d:\t%d\n", i++, ll->data);
ll = ll->next;
}
printf("%d:\t%d\n", i++, ll->data);
}
void magicpoker(node* ll)
{
int count_step = 0;
int i = 0;
//第一张始终是1
ll->data = 1;
count_step = 2;
while (1)
{
for (i = 0; i < count_step; i++)
{
ll = ll->next;
if (ll->data != 0)
{
i--; //增加循环次数,就变相步过不为0的节点。
}
}
if (ll->data == 0)
{
ll->data = count_step;
//ll = ll->next;
count_step++;
if (count_step == 14)
{
break;
}
}
}
}
int main()
{
create_list(13);
magicpoker(ghead);
printlist(ghead);
system("pause");
}
结果:
1: 1
2: 8
3: 2
4: 5
5: 10
6: 3
7: 12
8: 11
9: 9
10: 4
11: 7
12: 6
13: 13