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

原文地址为: 魔术师发牌问题和拉丁布方阵

本文利用经典的魔术师发牌问题与拉丁法阵分别讲解了循环链表与单向链表的使用,作为算法中的经典,对于链表的学习和理解都有着很大的帮助,不妨一看。


魔术师发牌问题

问题描述:

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

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

经典循环链表问题,代码如下:


#include<iostream>
using namespace std;
// 循环链表结构体
typedef struct _Node
{
    int data;  // 数据域;
    struct _Node *next;   // 指针域;
}DNode,*DLinkList;

// 初始化函数
void InitDLinkList(DLinkList *pHead)
{
    *pHead = new DNode;
    (*pHead)->data = 0;
    (*pHead)->next = *pHead;
}

// -----------------------------------------魔术师发牌问题--------------------------------

// 显示发牌顺序
void ShowMagic(DLinkList pHead)
{
    
    DLinkList nPos = pHead;
    while (nPos->next!=pHead)
    {
        cout << nPos->data << ",";
        nPos = nPos->next;
        
    }
    cout << nPos->data << endl;
}

// 初始化函数
void MCreate(DLinkList *pHead, int count)
{
    InitDLinkList(pHead);
    DLinkList nPos = *pHead;
    for (int i = 0; i < count; i++)
    {
        InsertTailDLinkList(pHead, i+1);
    }
    while (nPos->next!=*pHead)
    {
        nPos = nPos->next;
    }
    // 释放头结点
    DLinkList temp = *pHead;
    (*pHead) = temp->next;
    nPos->next =*pHead;
    delete temp;
    temp = NULL;
}

// 获取长度
int GetDLLength(DLinkList pHead)
{
    int count= 1;
    DLinkList nPos = pHead;
    while (nPos->next!=pHead)
    {
        nPos = nPos->next;
        count++;
    }

    return count;
}
// 发牌顺序
void MSort(DLinkList *pHead)
{
    int CountNum = 2;   //
    DLinkList nPos = (*pHead);
    nPos->data = 1;
    int len = GetDLLength(*pHead);  // 链表长度
    while (CountNum <=len)
    {
        int i;
        for ( i = 0; i < CountNum; i++)
        {

                nPos = nPos->next;
                if (nPos->data != 0)
                {
                    //    nPos = nPos->next;
                    i--;

                }
        }
        if (nPos->data==0)
        {
            nPos->data = CountNum;
            CountNum++;
        }

    }
}


// 魔术师发牌问题测试程序
void test()
{
    DLinkList pHead = NULL;
    int DNodeNum = 0;  // 结点个数
    cout << "请输入结点个数:" << endl;
    cin >> DNodeNum;
    MCreate(&pHead,DNodeNum);
    MSort(&pHead);
    cout << "发牌顺序为:" << endl;
    ShowMagic(pHead);

    DestoryDLinkList(&pHead);
}

int main2(void)
{
    test();
    return 0;
}


拉丁方阵问题

 问题描述:

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

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

例如:

1      2      3

2      3      1

3      1      2

问题:如何构造N阶拉丁方阵?普通代码如下:(N阶所有拉丁方阵)


//----------------------------------------------拉丁布方阵问题----------------------------------

// 建立方阵函数
void SetMatrix(DLinkList pHead,int len)
{

    int count = 0;
    int i, j,k;
    for (i=0;i<len;i++)  // 行
    {
        DLinkList nPos = pHead;
        for (j = 0; j < i; j++)   // 移动结点位置  第 i 行到链表第 i+1 个位置
        {
            nPos = nPos->next;
        }
        for (k = 0; k < len; k++)       //  列输出
        {
            cout << nPos->data << "    ";    // 输出元素
            nPos = nPos->next;
        }
        cout << endl;
    }
}

// 拉丁布方阵测试程序
void test2()
{
    DLinkList pHead = NULL;
    int arr[3][3] = { 0 };
    cout << "请输入方针的阶数:" << endl;
    int num = 0;
    cin >> num;
    MCreate(&pHead, num);
    SetMatrix(pHead,num);
}
int main(void)
{
    test2();

    return  0;
}

转载请注明本文地址: 魔术师发牌问题和拉丁布方阵

猜你喜欢

转载自blog.csdn.net/wangchaoqi1985/article/details/80950343