欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 手游 > 约瑟夫问题

约瑟夫问题

2025/6/22 5:37:03 来源:https://blog.csdn.net/jiang_sanmu/article/details/148814103  浏览:    关键词:约瑟夫问题

UVA133 救济金发放

题目描述

n n n 个人站成一圈,逆时针编号为 1 ∼ n 1\sim n 1n。有两个官员, A \text{A} A 1 1 1 开始逆时针数, B \text{B} B n n n 开始顺时针数。

在每一轮中,官员 A \text{A} A k k k个就停下来,官员 B \text{B} B m m m 个就停下来(两个官员有可能能停在同一个人上)。接下来被官员选中的 1 1 1 个或 2 2 2个人离开队伍。

输出离开队伍的顺序,如果有两个人,先输出 A 选中的。

输入格式

本题多测

对于每组数据,输入共一行,输入 n , k , m n,k,m n,k,m

数据以 0 0 0 \texttt{0 0 0} 0 0 0 结尾。

输出格式

对于每组数据,输出一行,为离开队伍的顺序。

输出的每个数应正好占 3 3 3 列。

样例中的“ ␣ ”代表一个空格。

输入输出样例 #1

输入 #1

10 4 3
0 0 0

输出 #1

␣␣4␣␣8,␣␣9␣␣5,␣␣3␣␣1,␣␣2␣␣6,␣10,␣␣7

说明/提示

数据范围

对于 100 % 100\% 100% 的数据,满足 0 < n < 20 0<n<20 0<n<20 0 < k , m 0<k,m 0<k,m

方法一:

使用数组或列表模拟队列
使用一个数组/向量来保存还留在队列中的人。
每次在当前列表中找到要被淘汰的人的位置:
第一次顺时针找第 k 个;
第二次逆时针找第 m 个(注意是反方向);
删除该人并记录其编号;
直到队列为空为止。

关键点:

如何高效地处理“环”结构?可以用取模 % 来实现循环查找;
注意删除元素后,索引的变化;
注意方向变化(正向 vs 反向)。

int go(int p, int d, int t)//寻找下一个选中的人
{while (t--){do {p = (p + d + n - 1) % n + 1;} while (arr[p] == 0);}return p;
}

上面的代码是解决约瑟夫问题的关键
p:代表当前位置
d是代表移动的方向,1代表逆时针移动,-1代表顺时针移动,
t:要移动的步数(即第几个有效的人)
以10 4 3为例
初始A在第一个位置,需要数4次,分别是1,2,3,4
所以设置A的初始位置p=0,移动方向d = 1,移动次数 t = k = 4
初始B在第十个位置,需要数3次,分别是10,9,8
所以设置B的初始位置p = 11,移动方向 d = -1,移动次数 t = m =3
如果查找下一个位置没有人,也就是arr[p]==0,那就继续找下一个

p = (p + d + n - 1)%n + 1

这里加 n-1 的作用就是实现环形数组的循环,为什么不是+n而是n-1呢
因为%模运算后的结果在[ 0 , n-1 ],但是原数组的下标是 [ 1 , n ],也就是说原本的数组范围要先映射到模运算的数组范围,最后再还原成原数组下标,也就是+1 的原因。

代码

#include <bits/stdc++.h>
using namespace std;
int n, k, m;
int arr[25];
int go(int p, int d, int t)
{while (t--){do{p = (p + d + n - 1) % n + 1;} while (arr[p] == 0);}return p;
}
int main()
{while (cin >> n >> k >> m){if (!n && !k && !m)break;for (int i = 1; i <= n; i++)arr[i] = i;int res = n;int p1 = 0, p2 = n + 1;while (res){p1 = go(p1, 1, k);p2 = go(p2, -1, m);arr[p1] = 0;res--;printf("%3d", p1);if (p2 != p1){res--;arr[p2] = 0;printf("%3d", p2);}if (res)printf(",");}cout << endl;}return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词