魔术师发牌问题的简介:一位魔术师掏出一叠扑克牌,魔术师取出其中13张黑桃,洗好后,把牌面朝下。说:“我不看牌,只数一数就能知道每张牌是什么?”魔术师口中念一,将第一张牌翻过来看正好是A;魔术师将黑桃A放到桌上,继续数手里的余牌,第二次数1,2,将第一张牌放到这叠牌的下面,将第二张牌翻开,正好是黑桃2,也把它放在桌子上。第三次数1,2,3,前面二张牌放到这叠牌的下面,取出第三张牌,正好是黑桃3,这样依次将13张牌翻出,全部都准确无误。求解:魔术师手中牌的原始顺序是什么样子的?
#include <stdio.h>
#include <stdlib.h>
#define cardnum 13 // 一种花色的牌数
typedef struct node {
int data ;
struct node *next ;
} node ;
node *createlist (node *head) // 尾插法建立循环链表,不多赘述
{
node *tmp = NULL ;
node *add = NULL ;
head = (node *)malloc(sizeof(node));
tmp = head ;
for (int i = 0 ; i < cardnum ; i++)
{
add = (node *)malloc(sizeof(node));
add->data = 0 ;
tmp->next = add ;
tmp = add ;
}
tmp->next = head->next ;
return tmp->next ;
}
void magic (node *head) // 这个算法充分展示了循环链表的伟大之处
// 极其建议在纸上进行推演,会更快发现其算法的智慧之处,强烈建议
{
node *target = NULL ;
int i ;
int countnum = 2 ;
head->data = 1 ; // 翻开第一张牌,记录其数字,数据域被变动的结点后期会被忽略
target = head ; // 目标指针变量
while (1)
{
for (i = 0 ; i < countnum ; i++) // 第一次执行时,进行两次迭代,继而跳脱以翻开第二张牌
{
target = target->next ; // 步进目标指针
if (target->data != 0) // 如果数据域被改动过,即亮出来的卡片,则忽略它,使用i--不计这次迭代
{
i-- ;
}
}
target->data = countnum ;
// 来到我们准备翻开的牌,进行赋值操作
countnum ++ ; // 增加点数
if (countnum == 14) // 当点数为13的牌确立后,则在自增之后跳脱
{
break ;
}
}
}
int main ()
{
node *head = NULL ;
head = createlist(head);
magic(head);
printf("按以下顺序排列:\n");
for (int i = 0 ; i < cardnum ; i++)
{
printf("黑桃%d ",head->data);
head = head->next ;
}
}