[问题分析]
在"猴子选大王"问题的解决过程中, 我们给定猴子的数量和出圈报数k(从1开始报数, 数到k的猴子出圈, 下一只猴子再从1开始报数), 得到圈中所剩最后一只猴子的编号. 在"猴子钦定大王"问题中, 我们给定猴子的数量和圈中所剩最后一只猴子的编号, 得到最小的出圈报数k值.
这个问题不妨这样解决, 使用之前已写好的 f函数, 报数k值从2开始, 依次+1, 直到当前的出圈报数k值可以使圈中所剩最后一只猴子的编号和给定的编号相同, 此时即得到问题的解.
首先, 我们需要将之前的 f函数做一点修改: 将圈中所剩最后一只猴子的编号返回.
/* 报数报到k的猴子出圈, 返回最后剩下的那只猴子的编号 */
unsigned long f(unsigned long k)
{
/* 如果当前表内没有结点, 直接结束 */
if(head -> number == 0)
{
return ;
}
struct Node *p = head -> next;
struct Node *q = head;
/* 变量 i 存储下一只猴子的报数值 */
unsigned long i = 1;
/* 圈中猴子数量 ≥ 2, 循环继续进行 */
while(head -> number > 1)
{
if(i == k)
{
/* 计数变量 i 的值满足该结点出圈的条件 */
/* 但如果该结点是头结点, 应跳过该结点 */
if(p != head)
{
/* 将当前待出圈结点从循环链表中删除 */
q -> next = q -> next -> next;
free(p);
p = q -> next;
/* 圈中猴子数量-1 */
head -> number--;
/* 计数变量置1, 等待下一轮报数开始 */
i = 1;
}
else
{
p = p -> next;
q = q -> next;