Shuffling Machine、洗牌机器

题目来源:PTA(Programming Teaching Assistant) https://pintia.cn/problem-sets/17/problems/264

Shuffling Machine (20 分)

Shuffling is a procedure used to randomize a deck of playing cards. Because standard shuffling techniques are seen as weak, and in order to avoid “inside jobs” where employees collaborate with gamblers by performing inadequate shuffles, many casinos employ automatic shuffling machines. Your task is to simulate a shuffling machine.
The machine shuffles a deck of 54 cards according to a given random order and repeats for a given number of times. It is assumed that the initial status of a card deck is in the following order:
S1, S2, …, S13,
H1, H2, …, H13,
C1, C2, …, C13,
D1, D2, …, D13,
J1, J2
where “S” stands for “Spade”, “H” for “Heart”, “C” for “Club”, “D” for “Diamond”, and “J” for “Joker”. A given order is a permutation of distinct integers in [1, 54]. If the number at the i-th position is j, it means to move the card from position i to position j. For example, suppose we only have 5 cards: S3, H5, C1, D13 and J2. Given a shuffling order {4, 2, 5, 3, 1}, the result will be: J2, H5, D13, S3, C1. If we are to repeat the shuffling again, the result will be: C1, H5, S3, J2, D13.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer K (≤20) which is the number of repeat times. Then the next line contains the given order. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print the shuffling results in one line. All the cards are separated by a space, and there must be no extra space at the end of the line.

Sample Input:

2
36 52 37 38 3 39 40 53 54 41 11 12 13 42 43 44 2 4 23 24 25 26 27 6 7 8 48 49 50 51 9 10 14 15 16 5 17 18 19 1 20 21 22 28 29 30 31 32 33 34 35 45 46 47

Sample Output:

S7 C11 C10 C12 S1 H7 H8 H9 D8 D9 S11 S12 S13 D10 D11 D12 S3 S4 S6 S10 H1 H2 C13 D2 D3 D4 H6 H3 D13 J1 J2 C1 C2 C3 C4 D1 S5 H5 H11 H12 C6 C7 C8 C9 S2 S8 S9 H10 D5 D6 D7 H4 H13 C5

解题思路
1、首先要构造初始牌面,即S1~S13、H1~H13、C1~C13、D1~D13 和 J1~J13 共计54张牌;

2、如何表示一张牌面?理论上可以使用字符串(C语言中字符数组)来表示 “S1” 等一张牌面,本人这里采用的是”字符+整数“的形式来表示一张牌面, 即 “S1” 是 ‘S’ 字符和 整数 ‘1’组合而成的,这种表示很方便直观,不需要考虑字符串的一系列问题,其余牌面雷同;

3、采用两个数组,一个字符数组存储每一张牌面的字符部分,另一个整型数组存储每一张牌面的数字部分,两个数组大小相等,并且两个数组的每一个相同位置上的字符和数字具有一一对应的关系,是不可分割的;

4、读入的整数存放到一个整型数组中,下文将这个数组称为 “洗牌规则”,这个数组中每一个元素的意义表示如下:假设这个数组的名称为 shufflingOrder,并且 shufflingOrder[0] = 36、shufflingOrder[1] = 52,牌面的数组名称为 shufflingCards,并且 shufflingCards[0] = “S1”、shufflingCards[1] = “S2”,两者大小一致。此时要执行的操作是:将 shuffingCards[0] 中的值 “S1” 放到 shufflingCards 数组第36个位置上去,即应该让 shufflingCards[35] = “S1”;shuffingCards[1] 中的值 “S2” 放到 shufflingCards 数组第52个位置上去,即应该让 shufflingCards[51] = “S2”;

5、“洗牌规则”数组中的其余位置上的数字的作用雷同;

6、由于本人采用的存储牌面的方式是两个数组(一个字符数组,表示牌面的字符部分+一个整型数组,表示牌面的整数部分)组合使用,所以在操作的时候必须两个数组同时在相同的位置进行相同的操作(也不麻烦)。

7、一次“洗牌规则”完成后,执行K次这样的操作,输出所有的牌面即可。注意:本人的存储和表示方式特别,所以在输出的时候两个数组同时输出,即相同的位置先输出字符数组的值,然后输出整型数组的同一个位置的
值,然后取下一个位置即可。

扫描二维码关注公众号,回复: 2558463 查看本文章

C语言代码如下:

/* 标准输入输出和标准库头文件 */
#include<stdio.h>
#include<stdlib.h>

/* 宏定义 */
/* 牌面的总数,牌一共有54张 */
#define SHUFFLINGCARDS 54
/* 一种花色的牌有13张 */
#define NUMBERSINEACHLINE 13

/* 自定义函数 */
/* 函数功能:洗牌机器,自动洗牌 */
/* 参数:“见名知意”
/*      toShufflingCardsOfPartOfCharacter是等待洗牌的牌面字符部分组成的数组 */
/*      toShufflingCardsOfPartOfInteger是等待洗牌的牌面整数数字部分组成的数组 */
/*      shufflingOrder是存放的洗牌顺序,也即是洗牌的规则 */
/*      K是洗牌的次数,即按照当前洗牌规则的洗牌次数 */
/* 这里假设传入的参数都是合法的并且合理的 */
/* toShufflingCardsOfPartOfCharacter、toShufflingCardsOfPartOfInteger和shufflingOrder的大小必须一致,保证一一对应,K应该是大于等于0的整数 */
void shuffingMachine(char toShufflingCardsOfPartOfCharacter[], int toShufflingCardsOfPartOfInteger[], int shufflingOrder[], int K)
{
    /* 循环执行“洗牌”的动作,洗牌次数为K */
    for (int countTimes = 1; countTimes <= K; ++countTimes)
    {
        /* 一个临时的字符数组tempToShufflingCardsOfPartOfCharacter保存牌面的字符部分一次洗牌后的结果 */
        char tempToShufflingCardsOfPartOfCharacter[SHUFFLINGCARDS];

        /* 一个临时整型数组tempToShufflingCardsOfPartOfInteger保存牌面的整型数字部分一次洗牌后的结果 */
        int tempToShufflingCardsOfPartOfInteger[SHUFFLINGCARDS];

        /* 按照shufflingOrder数组中存放的“规则”进行洗牌 */
        for (int i = 0; i < SHUFFLINGCARDS; ++i)
        {
            /* 具体规则:shufflingOrder[i]中存放的是地址,是toShufflingCardsOfPartOfCharacter[i]中字符应该放入的地址(其值[1,54],和数组[0,54)相差1,所以减去1),这里保存到临时字符数组中 */
            tempToShufflingCardsOfPartOfCharacter[shufflingOrder[i] - 1] = toShufflingCardsOfPartOfCharacter[i];

            /* 具体规则:shufflingOrder[i]中存放的是地址,tempToShufflingCardsOfPartOfInteger[i]中整数应该放入的地址(其值[1,54],和数组[0,54)相差1,所以减去1),这里保存到临时整型数组中 */
            tempToShufflingCardsOfPartOfInteger[shufflingOrder[i] - 1] = toShufflingCardsOfPartOfInteger[i];
        }

        /* 将tempToShufflingCardsOfPartOfCharacter中一次洗牌后字符的结果放回原字符数组toShufflingCardsOfPartOfCharacter中 */
        /* 将tempToShufflingCardsOfPartOfInteger中一次洗牌后整数的结果放回原整型数组toShufflingCardsOfPartOfInteger中 */
        for (int i = 0; i < SHUFFLINGCARDS; ++i)
        {
            toShufflingCardsOfPartOfCharacter[i] = tempToShufflingCardsOfPartOfCharacter[i];
            toShufflingCardsOfPartOfInteger[i] = tempToShufflingCardsOfPartOfInteger[i];
        }
    }
}




/* 主函数 */
int main()
{
    /* K代表洗牌次数(这里为了和题目吻合,没有另取名称) */
    int K = 0;

    /* 牌面的字符部分组成的字符数组,大小为牌面的数目 */
    char shufflingCardsOfPartOfCharacter[SHUFFLINGCARDS];

    /* 牌面的整数部分组成的整型数组,大小为牌面的数目,和字符数组大小保持一致 */ 
    /* 因为有一一对应的关系,一张牌面是shufflingCardsOfPartOfCharacter[i]+shufflingCardsOfPartOfInteger[i]组成的(这里的i范围[0,54),且是同一个i) */
    int shufflingCardsOfPartOfInteger[SHUFFLINGCARDS];

    /* 洗牌规则(顺序,次序),大小为牌面的数目,和前两个数组大小保持一致,因为具有一一对应的关系 */
    int shufflingOrder[SHUFFLINGCARDS] = { 0 };

    /* 初始化字符数组,形成以下形式的字符数组 */
    /* 
        S1, S2, ..., S13,   
        H1, H2, ..., H13,   
        C1, C2, ..., C13,  
        D1, D2, ..., D13,  
        J1, J2, ..., J13 
    */
    /* 注意,看起来像是二维数组,其实是一维数组。使用一维数组操作更便捷,不容易出错 */
    /* 如果有不信的,可以自己用二维数组操作,自己实验一下 */
    for (int i = 1; i <= SHUFFLINGCARDS; ++i)
    {
        char characterNumber = 0;
        /* 第一个13个字符存放‘S’ */
        if (i <= NUMBERSINEACHLINE)
        {
            characterNumber = 'S';
        }
        /* 第二个13个字符存放‘H’ */
        else if (i <= 2 * NUMBERSINEACHLINE)
        {
            characterNumber = 'H';
        }
        /* 第三个13个字符存放‘C’ */
        else if (i <= 3 * NUMBERSINEACHLINE)
        {
            characterNumber = 'C';
        }
        /* 第四个13个字符存放‘D’ */
        else if (i <= 4 * NUMBERSINEACHLINE)
        {
            characterNumber = 'D';
        }
        /* 第五个13个字符存放‘J’ */
        else if (i <= 5 * NUMBERSINEACHLINE)
        {
            characterNumber = 'J';
        }

        /* 将字符存入字符数组对应位置 */
        shufflingCardsOfPartOfCharacter[i - 1] = characterNumber;

        /* 不能单纯的采用求余的方法,必须和if联合使用才能达到目的 */
        /* 存入[1,12] */
        if (0 != i % NUMBERSINEACHLINE)
        {
            shufflingCardsOfPartOfInteger[i - 1] = i % NUMBERSINEACHLINE;
        }
        /* 存入NUMBERSINEACHLINE=13 */
        else
        {
            shufflingCardsOfPartOfInteger[i - 1] = NUMBERSINEACHLINE;
        }

    }
    // input.
    /* 从控制台接收输入 */
    /* 首先读入洗牌次数K */
    scanf_s("%d", &K);

    /* 接着读入洗牌规则(顺序,次序),共SHUFFLINGCARDS=54个正整数,不能多也不能少 */
    for (int i = 0; i < SHUFFLINGCARDS; ++i)
    {
        scanf_s("%d", &shufflingOrder[i]);
    }


    // process.
    /* 处理--“洗牌” */
    shuffingMachine(shufflingCardsOfPartOfCharacter, shufflingCardsOfPartOfInteger, shufflingOrder, K);

    // output.
    /* 输出:洗牌过后的牌面顺序 */
    /* 注意:shufflingCardsOfPartOfCharacter[i]和shufflingCardsOfPartOfInteger[i]是一一对应的,前者和后者组合起来才是一张牌面 */
    for (int i = 1; i <= SHUFFLINGCARDS; ++i)
    {
        printf("%c%d", shufflingCardsOfPartOfCharacter[i - 1], shufflingCardsOfPartOfInteger[i - 1]);
        /* 确保最后一张牌面后面没有多余的空格 */
        if (i != SHUFFLINGCARDS)
        {
            printf(" ");
        }
    }
    /* 输出完成后,换行 */
    printf("\n");
    return 0;
}

运行结果:

如果编译报错 “scanf not safe,please use scanf_s instead”,只需要替换 “scanf” 为 “scanf_s” 即可。

猜你喜欢

转载自blog.csdn.net/PursueLuo/article/details/80000910
今日推荐