【算法百题之四】约瑟夫环变形问题
大家好,我是Lampard~~
很高兴又能和大家见面了,接下来继续更新的是算法题,一日一练,早日升仙!
今天的问题是:
现在有50个人围圈圈,选其中一个人开始报数出列,然后每隔一人循环报数出列直至剩下最后一人为止。问题是:现在我想最后一个人是42号选手,那么请问我该从第几号开始数起呢?
(默认初始的人按顺序存放在一维数组中)
我的思路:
从一开始看到这个问题的时候,内心bb:
42最后?那我大胆猜测它是从41开始数起的!!!
手写了一遍后,不对。
那肯定是从43开始的!!!
再写了一遍后,还是不对。
啊!我的脑子快疼死了,怎么还不对!!(等等,我根本没有脑子)
既然手写算不出来,为何不用编程实现呢?我不单只要写出42最后是谁开始数,我还要随便输入一个最后输出的数,要程序就返回给我开始数的位置!!!于是,代码,它来啦!!!
#include "pch.h"
#include <iostream>
#include <queue>
#include <string>
using namespace std;
int Key;
int GetNum(int* array)
{
int num = 2;
// num是报数的数字,当num==2时出列
queue <int> A;
queue <int> B;
// 第一步把一维数组里面的名字转进去队列A处
for (int i = 0; i < 50; i++)
{
if (num == 2)
{
num = 1;
}
else
{
num++;
A.push(array[i]);
}
}
int flag = 1;
// flag是判断队列AB是否都为空,flag==1时,A非空,flag == 2时,B非空,flag == 0时,AB
while (flag != 0)
{
if (flag == 1)
{
// 从队列A转队列B
while (A.size() != 0)
{
if (num == 2)
{
num = 1;
A.pop();
}
else
{
num++;
B.push(A.front());
A.pop();
}
}
// 判断B是否为空
if (B.size() != 1)
flag = 2;
else
flag = 0;
}
else if (flag == 2)
{
while (B.size() != 0)
{
if (num == 2)
{
num = 1;
B.pop();
}
else
{
num++;
A.push(B.front());
B.pop();
}
}
// 判断A是否为空
if (A.size() != 1)
flag = 1;
else
flag = 0;
}
}
if (A.size() != 0)
return A.front();
else if (B.size() != 0)
return B.front();
else if (A.size() == 0 && B.size() == 0)
return 0;
}
int main()
{
int result[50];
for (int i = 0; i < 50; i++)
{ // 用了双重循环,待优化
int array[50];
for (int k = 0; k < 50; k++)
{
array[k] = ((i+k) % 50)+1; // 记得求余哦
}
result[i]=GetNum(array);
}
cout << "请输入想要最后输出的数:" << endl;
cin >> Key;
for (int j = 0; j < 50; j++)
{
if (result[j] == Key)
{
cout << "从第:" << j + 1<< "位开始数起。" <<endl;
break;
}
}
}
上面有我的注释,简单来说就是依据我昨天写的约瑟夫环代码封装成一个函数GetNum()。
然后把每三个人出列,改成每两个人出列。
比较麻烦的是之前我封装的函数是默认从第array【0】位开始出列
那么如果我们想要实现不同位置开始出列,就只能把数组存储内容的顺序进行改变
(例如如果想第一个出列的是第6号兄弟,那么array【0】=6;以此类推)
然后用一个一维数组按顺序存储结果。
最后只需要遍历这个结果数组,你就知道找到你想输出的答案,人那么你就可以把它的索引输出来啦!
测试结果:
OK,今天的博客就到这里,谢谢大家!!!