本文共 1741 字,大约阅读时间需要 5 分钟。
问题描述:
魔术师利用一副牌中的13张黑牌,预先将他们排好后叠放在一起,牌面朝下。对观众说:“我不看牌,只数数就可以猜到每张牌是什么,我大声数数,你们听,不信?现场演示。”魔术师将最上面的那张牌数为1,把他翻过来正好是黑桃A,将黑桃A放在桌子上,第二次数1,2,将第一张牌放在这些牌的下面,将第二张牌翻过来,正好是黑桃2,也将它放在桌子上这样依次进行将13张牌全部翻出,准确无误。
问题:牌的开始顺序是如何安排的?
用循环链表来解决
解题思路:好像是约瑟夫问题的反向求解。先看一下图
下方是已知的最后顺序,且已知循环链表有13个元素,所以建立13个空格代表循环链表,从1开始依次往里填入数,只能数空的空格,有数的空格要跳过,因为数到的牌会被抽走,最后填满如图所示,按照这个思路写代码。
public class MoshushifapaiTest { public static void magician(){ Node first = new Node(1); first.nextNode = first; Node last = first; // 1:先创建一个空的 循环链表,确定一个位置为起始位置,data为1 for(int i = 2;i<14;i++){ Node next = new Node(); next.nextNode = first; last.nextNode = next; last = next; } // 2:从data为1node的下一个node开始数,数两个,依次填入牌的号码,// 直到数到最大的13次,将13填入循环链表中 Node now = first; for(int i=2;i<14;i++){ int j = 1;// i:应该数的次数,比如填入i时,应该在链表中数i次。// j:实际数的次数,比如填入i时,应该数i次,当时当前数到了j次,j<=i// 当 i=j 时往循环链表中填入 当前数字 // 从填入的下一个开始数1 Node next = now.nextNode; while(true){ // data 为0 说明是空的node,如果不是空的node 要跳过,且不记录数的次数 if(next.data==0){ // 当应该数的次数和实际数的次数相等时,往当前node填入此数,并且now为当前node if(j==i){ next.data = i; now = next; // 跳出while break; } j++; } next = next.nextNode; } } System.out.println(); while(true){ now = first; boolean flag = true; while(true){ if(now.data!=1){ System.out.print(now); now = now.nextNode; }else if(now.data==1&&flag){ System.out.print(now); flag = false; now = now.nextNode; }else{ break; } } break; } } public static void main(String[] args) { magician(); }}class Node{ int data; Node nextNode; public Node(int data){ this.data = data; } public Node(){ } @Override public String toString() { return "|黑桃"+data+"|"; }}