魔术师发牌问题的简介:一位魔术师掏出一叠扑克牌,魔术师取出其中13张黑桃,洗好后,把牌面朝下。说:“我不看牌,只数一数就能知道每张牌是什么?”魔术师口中念一,将第一张牌翻过来看正好是A;魔术师将黑桃A放到桌上,继续数手里的余牌,第二次数1,2,将第一张牌放到这叠牌的下面,将第二张牌翻开,正好是黑桃2,也把它放在桌子上。第三次数1,2,3,前面二张牌放到这叠牌的下面,取出第三张牌,正好是黑桃3,这样依次将13张牌翻出,全部都准确无误。求解:魔术师手中牌的原始顺序是什么样子的?
使用php解决这个问题
解决思路是:
我们利用环形链表来解决,首先创建一个拥有13个节点的环形链表,创建一个while循环 循环的次数不能超过14次因为一共只有13张牌(我们假设每一张牌找到它自己对应的位置,需要一次循环),每一次魔术师都会从1开始数数,因为数字是连续的所以他下一次数的时候都会比前一次多数一次(我们将其数数的次数计为$count,初始化为$count=1,每找到一张牌,都会$count++的变化),我们通过一个for循环模拟魔术师数数的次数,循环次数小于$count ,他每次数的时候。我们将环形链表的指针向下
移一个节点。本次数数结束的时候我们向链表中将数到的最后的数添加到链表的位置,插入的条件是。链表的节点必须没有插入过数字
/**
* 环形链表的实现
* 魔术师发牌算法
*/
class poker
{
public $no;//序号
public $next=null;//指向下个节点的指针
public function __construct($no=''){
$this ->no = $no;
}
}
/**
* 创建一个环形链表
* @param $first object 链表的头节点
* @param $num integer 需要添加节点的数量
*/
function create(&$first,$num)
{
$cur = null;
for ($i=0;$i<$num;$i++)
{
$poker = new poker(0);
if ($i==0)
{
$first = $poker;
$first->next = $first;//将链表的尾节点指向头节点 形成环形链表
$cur = $first;//链表的头节点不能动 需要交给一个临时变量
} else {
$cur->next = $poker;
$cur->next->next = $first;//将链表的尾节点指向头节点 形成环形链表
$cur = $cur->next;
}
}
}
/**
* 遍历环形链表
* @param $first object 环形链表的头
*
*/
function view($first)
{
//头节点不能动,交个一个临时变量
$cur = $first;
while ($cur->next!=$first)
{
echo $cur->no.'--';
$cur = $cur->next;
}
//当退出循环的时候$cur->next=$first 刚好会忽略当前节点本身的遍历 所以退出的时候还要输出一下 否则会少遍历一个节点
echo $cur->no;
}
//创建一个拥有13个节点的环形链表
$first = null;
create($first,13);
/**
* 解决魔术师发牌问题
* @param $first null 头节点
* return 最后返回扑克牌的原始排放顺序
*/
function show(&$first)
{
$count = 1;//从1开始数
$length = 13;//总共13张牌
//头节点不能动
$cur = $first;
while($count!=14)
{
for ($i=0;$i<$count;$i++)
{
if ($count!=1) $cur = $cur->next;
if ($cur->no!==0) $i--;
}
//退出循环的时候说明找到了扑克牌该存放的位置
$cur->no = $count;
$count++;
}
}
//调用方法解决魔术师发牌问题
show($first);
echo '<br/>************扑克牌的原始排放顺势是*******'.'</br>';
view($first)