华师一附中OI组
标题:
反约瑟夫问题
[打印本页]
作者:
admin
时间:
2020-7-11 07:54
标题:
反约瑟夫问题
初始的约瑟夫问题是:m个人围成一个圈,从第一个人开始报数,报到n就出圈,下次不再参与报数,求最后一个出圈的人的编号k,假设m=8,n=5,那么k=3。
反约瑟夫是已知m和k,求最小的n。
类似的题目还有P1145
https://www.luogu.com.cn/problem/P1145
作者:
admin
时间:
2020-7-11 07:58
约瑟夫问题我们讲过,我以前给你们的写法如下,注意体会每句话的意思:
#include<iostream>
using namespace std;
int a[10];
int i,s,j,lst;
int main()
{
int m=8,n=5;
for (i=1;i<=m;i++) a[i]=1;///初始都在圈内
i=s=j=0;
while (j<=m-1)
{
i++;
if (i>m) i=1;///围圈
s=s+a[i];///报数
if (s==n) {
a[i]=0;//出圈
s=0;
cout<<i<' ';
j++;///+1
}
}
return 0;
}
/// m=8 n=5 k=3
复制代码
作者:
admin
时间:
2020-7-11 08:03
现在我们不是要求输出出圈的顺序,只要求输出最后一个出去的人,要怎么改呢?
直接把地18行的cout<<i挪到renturn 0 的前面就行了吧!这个逻辑体会下。
#include<iostream>
using namespace std;
int a[10];
int i,s,j;
int main()
{
int m=8,n=5;
for (i=1; i<=m; i++) a[i]=1; ///初始都在圈内
i=s=j=0;
while (j<=m-1)
{
i++;
if (i>m) i=1;///围圈
s=s+a[i];///报数
if (s==n)
{
a[i]=0;//出圈
s=0;
///cout<<i<<' ';
j++;///+1
}
}
cout<<i<<' ';
return 0;
}
/// m=8 n=5 k=3
复制代码
作者:
admin
时间:
2020-7-11 08:12
现在我们是已知m和k,求最小的n,是不是可以用穷举法,让n从1开始循环,依次求出k,当符合条件的时候,就不再做了。
那么第7行,就不是n=5,改成for(n=1;n<=m;n++),第8到第23行都要被放在n的这个循环里面去。
#include<iostream>
using namespace std;
int a[10];
int i,s,j;
int main()
{
int m=8,n;
for (n=1; n<=100; n++)
{
for (i=1; i<=m; i++) a[i]=1; ///初始都在圈内
i=s=j=0;
while (j<=m-1)
{
i++;
if (i>m) i=1;///围圈
s=s+a[i];///报数
if (s==n)
{
a[i]=0;//出圈
s=0;
///cout<<i<<' ';
j++;///+1
}
}
cout<<i<<' ';
}
return 0;
}
/// m=8 n=5 k=3
复制代码
现在是依次求出了n=1,2,3,4,5***100时最后一个出去的人,那么在cout<i的地方加一个判断,符合条件就不再做了就行,比较严密的的做法是类似质数判断,再设一个变量b,简单的做法是直接在那里break,但是记住break只能跳出一层循环,千万注意。
作者:
admin
时间:
2020-7-11 08:12
最终代码如下:
#include<iostream>
using namespace std;
int a[10];
int i,s,j;
int main()
{
int m=8,n,k=3;
bool b=1;
for (n=1; n<=m& b==1; n++)
{
for (i=1; i<=m; i++) a[i]=1; ///初始都在圈内
i=s=j=0;
while (j<=m-1)
{
i++;
if (i>m) i=1;///围圈
s=s+a[i];///报数
if (s==n)
{
a[i]=0;//出圈
s=0;
///cout<<i<<' ';
j++;///+1
}
}
if (i==k) b=0;
}
cout<<n;
return 0;
}
/// m=8 n=5 k=3
复制代码
作者:
admin
时间:
2020-7-11 08:15
用函数的思想包装一下,设一个函数int ysf(m,n),表示输入m和n的时候求出k,那么程序就会变得更清晰易读:
#include<iostream>
using namespace std;
int a[10];
int i,s,j;
int ysf(int m,int n)
{
for (i=1; i<=m; i++) a[i]=1; ///初始都在圈内
i=s=j=0;
while (j<=m-1)
{
i++;
if (i>m) i=1;///围圈
s=s+a[i];///报数
if (s==n)
{
a[i]=0;//出圈
s=0;
///cout<<i<<' ';
j++;///+1
}
}
return i;
}
int main()
{
int m=8,n,k=3;
n=1;
while (ysf(m,n)!=k) n++;
cout<<n;
return 0;
}
/// m=8 n=5 k=3
复制代码
作者:
admin
时间:
2020-7-11 08:40
最后扩展思考:
1、是不是每个人都有可能成为最后一个出去的人?
2、若不限定n最小,可能有多个n满足条件,这些n之间有什么关系?
欢迎光临 华师一附中OI组 (http://hsyit.cn/)
Powered by Discuz! X3.2