Java实现2024春晚刘谦扑克牌魔术(约瑟夫环问题)

首先祝大家新年快乐!

刘谦带领全国人民一起玩扑克牌魔术。有网友形容,好像是一场规模巨大的春晚团建。也有人表示,刘谦魔术回归,熟悉的感觉又回来了。在这个魔术中你是否完成卡牌的配对呢?
在这里插入图片描述
其实这是一个经典约瑟夫环问题,有大佬已经通过数学公式推出来了:
小尼到底哪错了?北大同学揭秘春晚魔术

魔术过程

第一步:选出四张卡片ABCD。撕成两半,变成ABCDABCD

第二步:按名字数移动,不管移动几张,最后总是变成ABCDABCD(牌序变化,但搭配相对位置不变)

第三步:插3张卡片到中间,变成DXXXXXXD (中间是什么其实无所谓,只看两边)

第四步:将第一张卡片D藏好,XXXXXXD

第五步:按南方人北方人移动牌,依然是XXXXXXD

第六步:按男女扔牌,男:XXXXXD;女:XXXXD

第七步:见证奇迹的时刻,男:X1X2X3X4DX5;女:X1X2DX3X4

第八步:好运留下来!烦恼丢出去!

第一轮,男:X1X3D;女:X1DX4

第二轮,男:X1D;女:D

第三轮,男:D;女:D

到最后,藏好的卡片完美配对手里的卡片。

Java代码实现

package com.liuqian;

import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;

public class CardShuffle {
    public static void main(String[] args) {
        // 初始卡片cards队列,4张牌
        ArrayList<Integer> cards = new ArrayList<Integer>();
        cards.add(5);
        cards.add(3);
        cards.add(4);
        cards.add(9);
        System.out.println("卡牌 = " + cards);


        // 一、把4张牌撕开成8张,放到原来4张牌后
        int cardSize = cards.size();
        for (int i = 0; i < cardSize; i++) {
            cards.add(cards.get(i));
        }
        System.out.println("1.把4张牌撕开成8张 = " + cards);

        // 二、名字有几个字,名字有几个字就从队头拿几张牌放到队尾
        System.out.print("*你的名字:");
        Scanner scanner = new Scanner(System.in);
        int name_len = scanner.next().length();
        for (int i = 0; i < name_len; i++) {
            cards.add(cards.remove(0));
        }
        System.out.println("2.按名字取牌 = " + cards);

        // 三、拿起最上面三张,把这三张整体插进剩下卡片的中间任意位置  
        ArrayList<Integer> first_three = new ArrayList<Integer>(cards.subList(0, 3));
        ArrayList<Integer> other_cards = new ArrayList<Integer>(cards.subList(3, cards.size()));

        Random random = new Random();
        int index = random.nextInt(4) + 1;
        other_cards.addAll(index, first_three);
        cards = new ArrayList<Integer>(other_cards);
        System.out.println("3.拿起最上面三张插到任意位置 = " + cards);

        // 四、把第一张牌放到屁股下  
        int key_card = cards.remove(0);
        System.out.println("4.把第一张牌放到屁股下 = " + cards);
        System.out.println("屁股底下卡牌是:" + key_card);

        // 五、按南北方人取牌,重复上述过程
        System.out.print("*你是南方人还是北方人?");
        int south_north = scanner.next().startsWith("北") ? 1 : 2;
        ArrayList<Integer> first_cards = new ArrayList<Integer>(cards.subList(0, south_north));
        other_cards = new ArrayList<Integer>(cards.subList(south_north, cards.size()));

        index = random.nextInt(8 - south_north - 1) + 1;
        other_cards.addAll(index, first_cards);
        cards = new ArrayList<Integer>(other_cards);
        System.out.println("5.按南北方人取牌 = " + cards);

        // 六、按性别取牌,并撒出去
        System.out.print("*你是男生还是女生?");
        int gender = scanner.next().startsWith("男") ? 1 : 2;
        for (int i = 0; i < gender; i++) {
            cards.remove(0);
        }
        System.out.println("6.按性别取牌 = " + cards);

        // 七、洗牌,“见,证,奇,迹,的,时,刻”(经典的约瑟夫环问题)
        for (int i = 0; i < 7; i++) {
            cards.add(cards.remove(0));
        }
        System.out.println("7.简称奇迹的时刻 = " + cards);

        // 八、好运留下来,烦恼丢出去  
        while (cards.size() > 1) {
            cards.add(cards.remove(0));// 留下来
            cards.remove(0);// 丢出去
        }
        System.out.println("8.好运留下来,烦恼丢出去 = " + cards);
        System.out.println("[屁股底下那张牌:" + key_card + "] == [手里最后一张牌:" + cards.get(0) + "]");
        System.out.println();
        System.out.println("财运滚滚!龙年大吉!o(* ̄▽ ̄*)ブ");
    }
}

实验结果

在这里插入图片描述

约瑟夫环问题(Josephus Problem)是一个著名的数学问题,源于古代犹太历史学家弗拉维奥·约瑟夫斯(Flavius Josephus)的著作《犹太古代史》中的一个故事。根据故事内容,当时有一组被罗马军队包围的犹太人,他们决定宁愿自杀,也不愿被俘虏。于是,他们围成一个圆圈,从一个人开始,每隔一个人就自杀,直到剩下最后一个人。
这个问题提出了一个有趣的数学挑战:给定总人数n和每次报数的间隔m,如何确定最后剩下的那个人的位置?这个问题不仅有着深厚的数学背景,还涉及到算法设计和递归思想的应用。

往期遇到过的约瑟夫环问题:蓝桥杯 ADV-280 书院主持人

在解决约瑟夫环问题的过程中,可以使用循环、递归或数学公式等不同的方法。每种方法都有其优缺点,因此在实际应用中需要根据具体情况选择最合适的方法。

无论是从数学分析的角度,还是从算法实现的角度,约瑟夫环问题都是一个非常有趣和有挑战性的问题。它不仅能锻炼我们的数学思维能力,还能提升我们的算法设计和编程实现能力。

  • 27
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一条小传传

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值