C语言趣味编程 -- 魔术师手中的牌和圆圈最后剩下的人

问题:

  • 魔术师手中有A—K的黑桃牌13张,每次不看牌,数数:1翻过来恰好为A;一、2翻过来恰好为2;一、二、3翻过来恰好为3(不翻的牌放在手中这迭牌的最下面,翻开的牌翻开放在一侧);……;一、……、13恰好为K。最后放在一旁的牌的顺序为一、二、三、四、五、……、J、Q、K。问:原先魔术师手中的牌的循序是怎样的?
    • 解决这个问题咱们经过一个图来进行解释: 这里写图片描述
    • 这里咱们可以看到上面图中所表示的意思。图中刚开始有13个空白框,在第一个空白框中写入A、而后从下一个空白框开始计数(不是空白框的跳过),第二次数数时数到2在该框中写入2,第三次数到3写入3,依次类推,直到空白框
      被写满。咱们能够看到只是一个循环过程,循环的结束条件是空白框所有都被写入数字或字母。下面就给出C语言的代码:
#include<stdio.h>
int main()
{
   int i, j = 1;
   int arr[13] = {0};
   for(i = 1; i <= 13; i++)
   {
      int n = 1;
       while(n <= i)
       {
           if(j > 13)
           {
               j = 1;
           }
           if(arr[j])
           {
               j++;
           }
           else
           {
               if(n == i)
               {
                   arr[j] = i;
               }
               n++;
               j++;
           }
       }
   }
   return 0;
}
  • 这个问题的处理方法有不少种,这里就介绍了最基础的C语言解法,在咱们学过了数据结构后就能够利用循环链表和循环队来处理,相对好理解一点。web

  • 经过上面的问题,咱们还能过解决另一个问题:有N我的围成一圈,并将它们编号从1–N,而后开始报数,规定每隔M我的就淘汰一我的,问最后剩下的人为原先的几号?数组

    • 问题分析:这又是一个循环成圈的问题,由问题可知须要一个N个大小的空间来存放这些人的号码,而后每隔M我的淘汰一个,咱们能够理解为每次从1开始报数,报数为M+1的人淘汰,而后下一我的有从1开始报数,直到剩下最后一我的。先来演示一个例子:假设有10我的围成一圈,每隔2我的淘汰一我的。咱们能够知道N= 10,M= 2;这个问题咱们能够用一个大小为10个元素的整型数组来完成,依次将号码填入数组中,每次淘汰的人的号码咱们将其重新赋值为0,依次直到只剩下医德元素不为0结束,则最后留下的数字就为剩下最后一我的的号码。
      • 如图所示:这里写图片描述
    • 通过几回的循环后实现了要求,求出了最后剩下的人的号码。
    • 代码实现为:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void main()
{
    int m, n;
    printf("请输入人数N:");
    scanf_s("%d", &n);
    printf("请输入相隔M:");
    scanf_s("%d", &m);
    int *arr = (int *)malloc(sizeof(int) * n);
    for (int i = 0; i < n; i++)
    {
        arr[i] = i + 1;
    }
    int count = n;
    int k = 0, j = 0;
    while (count > 1)
    {
        if (arr[k] != 0)
        {
            j++;
        }
        if (j == m + 1)
        {
            arr[k] = 0;
            j = 0;
            count--;
        }
        k++;
        if (k == n)
        {
            k = 0;
        }
    }
    for (int i = 0; i < n; i++)
    {
        if (arr[i] != 0)
        {
            printf("最后剩下的号码为:%d\n", arr[i]);
        }
    }
    free(arr);
}
  • 总结:上面的两个问题均可以归为约瑟夫环的一类问题,正如上面所说的,解决这类问题最好理解的方法是利用数据结构中的循环队列和循环链表,但使用C语言中的数组来实现能够可让咱们加深对循环和数组的理解与应用,有开拓思惟的帮助。