经典报数问题
报数问题大致类似于约瑟夫环问题。
约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。通常解决这类问题时把编号从0~n-1,最后结果+1即为原问题的解。
之前做这类题型总是摸不着头脑,今天看了某大佬的文章后也算是茅塞顿开了,附上大佬的代码
1.模拟
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,m,s=0;scanf("%d",&n);
bool visit[200]={0};//visit赋初始值
for(int k=0;k<n;k++)
{//总共要出队n次
for(int i=0;i<3;i++){if(++s>n)s=1;if(visit[s])i--;}//类似取模,而因为序列是从1开始的,所以不取模,加判断;若visit过,则i--,使其继续循环
visit[s]=true;//输出,记录已出队
}
printf("%d ",s);
return 0;
}
注意判重 防止重复遍历
2.STL队列
#include<bits/stdc++.h>
using namespace std;
int main()
{
int tot, outNum, nowNum = 1;
queue<int> q;
cin >> tot; //读取数据
for (int i = 1; i <= tot; i++)q.push(i); //初始化队列
while (!q.empty()) //在队列不为空时继续模拟
{
if (nowNum == 3)
{
if(q.size()==1)
cout << q.front() << " "; //打印最后一个人的编号
q.pop(); //出局
nowNum = 1; //初始化现在的数字
}
else
{
nowNum++;
q.push(q.front()); //排至队尾
q.pop();
}
}
return 0;
}
3.优化后(On复杂度)
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n, m,i,s=0;
cin>>n;
for(i=2;i<=n;i++)
s=(s+3)%i;
printf("%d", s+1);
return 0;
}
总结
我个人感觉用队列比较好理解,正在努力理解其他方法。