【数据结构】求解魔术师发牌问题
题目描述
魔术师发牌问题的简介:一位魔术师掏出一叠扑克牌,魔术师取出其中13张黑桃,洗好后,把牌面朝下。说:“我不看牌,只数一数就能知道每张牌是什么?”魔术师口中念一,将第一张牌翻过来看正好是A;魔术师将黑桃A放到桌上,继续数手里的余牌,第二次数1,2,将第一张牌放到这叠牌的下面,将第二张牌翻开,正好是黑桃2,也把它放在桌子上。第三次数1,2,3,前面二张牌放到这叠牌的下面,取出第三张牌,正好是黑桃3,这样依次将13张牌翻出,全部都准确无误。求解:魔术师手中牌的原始顺序是什么样子的?
题目分析
从题目中我们可以看到,魔术师发牌的时候并不是连续发的,而是每次都隔着一定的步长,且步长递增,那么我们要做的就是按照他发牌的顺序来求解每一张牌,即先给第一张牌赋值1 , 然后数1 , 2给第3张牌赋值2,然后数1 , 2 ,3 给第6张牌赋值3…依此类推,并且因为中间间隔的牌还没赋值,所以我们赋值到末尾的时候还要从头开始继续赋值,所以我们可以采用循环链表来进行问题的求解。
#include <stdio.h>
#include <stdlib.h>
//牌数为13张
#define Number 13
//定义结点
typedef struct Node
{
int data;
struct Node *next;
} node;
//初始化循环链表
node* createlist()
{
node *head = NULL, *tail , *temp;
tail = head;
for(int i = 1 ; i <= Number ; i++)
{
temp = (node *)malloc(sizeof(node));
if(temp == NULL) //内存申请不成功时返回错误信息
exit(0);
temp->data = 0; //将每张牌的值初始化为0,后续如果牌面为0说名还没赋值
if(head == NULL)
head = temp;
else
tail->next = temp;
tail = temp; //更新尾指针
}
tail->next = head; //记得要链接起来,形成循环链表
return head;
}
void magic(node **head)
{
node *p; //p指针用于临时存放每次新的赋值 , 即用来遍历循环链表
p = *head;
p->data = 1; //第一张牌赋值为1
int countnumber = 2; //countnumber是每次的步数
while(1)
{
//定位要赋值的牌的位置
for (int i = 1 ; i <= countnumber ; i++)
{
p = p->next; //往下遍历
if(p->data != 0) //如果这张牌赋值过了就跳过
--i; //本次计的步长不算
}
p->data = countnumber; //找到位置后赋值
countnumber++;
if(14 == countnumber)
break;
}
}
int main(void)
{
node *head , *current;
head = createlist();
magic(&head);
current = head;
for(int i = 1 ; i <= Number ; i++)
{
printf("黑桃%d " , current->data);
current = current->next;
}
return 0;
}
OK!运行得到结果,验证一下没有错误。
黑桃1 黑桃8 黑桃2 黑桃5 黑桃10 黑桃3 黑桃12 黑桃11 黑桃9 黑桃4 黑桃7 黑桃6 黑桃13
--------------------------------
Process exited after 0.03923 seconds with return value 0
请按任意键继续. . .