魔术师发牌问题和拉丁方阵

本文探讨了魔术师如何通过特定的排列技巧实现发牌预测,利用循环链表解决这一问题。同时介绍了拉丁方阵的概念,这是一种n×n的方阵,每个元素出现且仅出现一次,以展示数学的巧妙应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

魔术师发牌问题

 

问题描述:

魔术师利用一副牌中的13张黑牌,预先将他们排好后叠放在一起,牌面朝下。对观众说:“我不看牌,只数数就可以猜到每张牌是什么,我大声数数,你们听,不信?现场演示。”魔术师将最上面的那张牌数为1,把他翻过来正好是黑桃A,将黑桃A放在桌子上,第二次数1,2,将第一张牌放在这些牌的下面,将第二张牌翻过来,正好是黑桃2,也将它放在桌子上这样依次进行将13张牌全部翻出,准确无误。

 

问题:牌的开始顺序是如何安排的?

 

请利用循环链表来解决

 

#include <stdio.h>
#include <stdlib.h>

#define  CardNumber 13

typedef struct node
{
    int data;
    struct node *next;
}sqlist, *linklist;

linklist CreateLinkList()
{
    linklist head = NULL;
    linklist s, r;
    int i;

    r = head;

    for(i=1; i <= CardNumber; i++)
    {
        s = (linklist)malloc(sizeof(sqlist));
        s->data = 0;

        if(head == NULL)
            head = s;
        else
            r->next = s;

        r = s;
    }

    r->next = head;

    return head;
}

// 发牌顺序计算
void Magician(linklist head)
{
    linklist p;
    int j;
    int Countnumber = 2;

    p = head;
    p->data = 1;  //第一张牌放1

    while(1)
    {
        for(j=0; j < Countnumber; j++)
        {
            p = p->next;
            if(p->data != 0)  //该位置有牌的话,则下一个位置,说明这张牌已经被拿出去了
            {
                p->next;
                j--;
            }
        }

        if(p->data == 0)
        {
            p->data = Countnumber;
            Countnumber ++;

            if(Countnumber == 14)
                break;
        }
    }
}

// 销毁工作
void DestoryList(linklist* list);

int main()
{
    linklist p;
    int i;

    p = CreateLinkList();
    Magician(p);

    printf("按如下顺序排列:\n");
    for (i=0; i < CardNumber; i++)
    {
        printf("黑桃%d ", p->data);
        p = p->next;
    }

    DestoryList(&p);

    return 0;
}

另一种实现:

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
const int cardNumber=13;
typedef struct Node
{
	int data;
	Node *next;
}node;
void CreateList(node **pHead)
{
	if((*pHead)==NULL)//表头元素
	{
		(*pHead)=(node*)malloc(sizeof(node));
		(*pHead)->data=0;
		(*pHead)->next=(*pHead);
	}
	node *cur=(*pHead);
	for(int i=1;i<cardNumber;i++)
	{
		node *tmp=(node*)malloc(sizeof(node));
		tmp->data=0;
		tmp->next=(*pHead);
		cur->next=tmp;
		cur=tmp;
	}

}
void MagicCard(node **pHead)
{
	(*pHead)->data=1;
	node *cur=(*pHead)->next;
	for(int i=2;i<=cardNumber;i++)
	{
		int j=1;
		while(j<i)
		{
			if(cur->data==0)
			{
				j++;
			}
			cur=cur->next;
		}
		while(cur->data!=0)
			cur=cur->next;
		cur->data=i;
	}

}
void Print(node *pHead)
{
	node *cur=pHead;
	for(int i=1;i<=cardNumber;i++)
	{

		printf("第%d张牌放的是:黑桃%d\n",i,cur->data);
		cur=cur->next;
	}
}
void DestroyList(node *pHead)
{
	node *s=pHead;
	int i=cardNumber;
	while(--i)
	{
		node *tmp=s;
		s=s->next;
		free(tmp);
		tmp=NULL;
	}
}
int _tmain(int argc, _TCHAR* argv[])
{
	node *pHead=NULL;
	CreateList(&pHead);
	MagicCard(&pHead);
	Print(pHead);
	DestroyList(pHead);
	system("pause");
	return 0;
}


拉丁方阵问题

 

拉丁方阵是一种n×n的方阵,方阵中恰有n种不同的元素,每种元素恰有n个,并且每种元素在一行和一列中 恰好出现一次。

著名数学家和物理学家欧拉使用拉丁字母来作为拉丁方阵里元素的符号,拉丁方阵因此而得名。

 

例如下图是一个3×3的拉丁方阵:

拉丁方阵

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值