魔术师的卡牌

此题目的:

  • 加深对循环链表的理解 
  • 增强对链表的使用能力

看到很多篇文章把这到问题写的不清不楚的,今天特意把这个题目叙述给大家,然后自己先想一想要怎么做。再来看题解。

某天,有个魔术师从一套完整的卡牌将13张张桃卡牌全部拿了出来,洗好了牌之后,展示给众人说,他对众人说,我不用看牌,只需要数数,就可以知道这张牌是什么,于是他把13张牌牌面向下,“第一张牌是 黑桃A”,他如此说道,然后把黑桃A扔到桌子上,此时手上还有12张牌,然后他又说道“从上往下数第二张牌是 黑桃2”,他把从上往下数的第一张牌拿到第12张牌,也就是最后一张牌的下面(没有看),然后翻看第二张牌,果真是是 黑桃2,然后他有说了“从上往下数第三张牌是 黑桃3”,于是他把前面两张牌按照原来的顺序放在最后一张牌的下面,翻开了第三张牌,果真是是 黑桃3,然后魔术师又把这张 黑桃3 扔到桌子上,就这样,反反复复,翻开了 13 张牌,魔术师说的每一张牌都是准确的,那么,他是怎么做到的呢?

问题转化:

其实就是一个魔术师在做翻牌之前,他是怎么放牌的问题。

首先,我们注意到,魔术师每次翻看完扑克牌以后,就把它扔到桌子上了,那么总的牌数就会减少。

其次,我们还注意到,每次魔术师翻看扑克牌之前都会把上面不翻看的扑克牌放到最下面。

魔术师做了 个动作,放牌    翻牌    扔牌,就这么重复这三种动作,所以答案肯定就在这个过程里面,假设我们固定 13 个盒子,将其标号为 1 - 13,如果盒子里面的扑克牌被翻看了,就为这个盒子盖上黑布,不准再碰了也不能在数数的时候算他一个,我们发现 当我们翻看 黑桃A 2 3 4 的时候,都是在 13 以内的,但是要翻 黑桃5 时,发现已经到最后一个盒子了,怎么办呢?我们想想魔术师怎么做的?---(放牌),没错,我们倒回去,从 1 号盒子开始,但是 1 号盒子已经被翻过了,不能再动它了,那这时候怎么办呢?死鬼,放聪明点,我们跳过这个 1 号格子不把它,到下一个盒子去,如果下一个盒子还这样我们继续跳过,前面留了这么多空,总会有没有翻过牌的盒子吧!(注意:无形中我们使用到了循环)

一张图看看:

 

需要用到循环,需要使用链表所以我们在开始解这项魔术之前要先定义循环链表哦!

#include <iostream>
#include <iomanip>
#include <malloc.h>
#include <memory.h>
#define N 13
using namespace std;

//定义链表结构体
typedef struct Node{
	int data;
	struct Node *Next;
}Node,*LinkList;

//初始化循环链表
LinkList InitLinkList(LinkList L)
{
	L = (Node*)malloc(sizeof(Node));
	L->Next = L;
	Node *p;
	for(int i = 0;i<N;i++)
	{
		p = (Node*)malloc(sizeof(Node));
		p->data = 0;
		p->Next = L->Next;
		L->Next = p;
	}
	return L;
}

int main()
{
	LinkList L = InitLinkList(L);
	
	int i;
	Node *p = (Node*)malloc(sizeof(Node));
	p = L->Next;
	p->data = 1;
    
    //放牌 翻牌 扔牌(就是跳过它,你也可以理解成跳牌)的过程
	for(int num = 2;num<=N;num++)
	{
		i = 0;
		while(i < num)
		{
			p = p->Next;	
			if(p->data == 0)
				i++;
		}
		p->data = i;
	}
	p = L->Next;
    //遍历
	while(p!=L)
	{
		cout<<p->data<<" ";
		p = p->Next;
	}
}

怎么样?有趣吧!是的,学算法也可以这么有趣!

猜你喜欢

转载自blog.csdn.net/szlg510027010/article/details/84585705