约瑟夫环问题的优化及终极优化

约瑟夫问题大致描述:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为1的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列,求最后一个出列人的编号。

算法1:模拟

链表维护每个人的相对位置,每次模拟报数的过程,每次踢掉一个人,求出最后被踢掉的人。

时间复杂度O(nm)

由于该算法比较暴力,就不贴呆马了

算法2:数学递推

考虑每次踢掉一个人后,问题会变成一个子问题,即(n-1)个人围一桌,从编号为上次被踢出的后一个人开始报数,数到m的人被踢掉,求出此次被踢掉的人的编号。

假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x‘=(x+k)%n;

所以这就变成了一个递推的问题:

令 f[i] 表示 i个人玩约瑟夫游戏,报到m的人被踢出,胜利的人的编号。

f[i]=(f[i-1]+m) % i; (i>1)   边界条件f[1]=0;

所以该问题可以递推解决,时间复杂度O(n)

1 var
2     n,k,i                                    :longint;
3     f                                        :array[0..1000050] of longint;
4 begin
5     read(n,k);
6     f[1]:=0;
7     for i:=2 to n do f[i]:=(f[i-1]+k) mod i;
8     writeln(f[n]+1);
9 end.

算法3:优化递推

上面的算法相比最初的模拟算法效率已经大大提升了,那么,该算法还有改进的余地么?
事实上,如果我们观察上述算法中的变量k,他的初始值为第一个出圈人的编号,但在循环的过程中,我们会发现它常常处在一种等差递增的状态,我来看这个式子:k = (k + m - 1) % i + 1,可以看出,当i比较大而k+m-1比较小的时候,k就处于一种等差递增的状态,这个等差递增的过程并不是必须的,可以跳过。
我们设一中间变量x,列出如下等式:
k + m * x – 1 = i + x
解出x,令k = k + m * x,将i + x直接赋值给 i,这样就跳过了中间共x重的循环,从而节省了等差递增的时间开销。
可是其中求出来的x + i可能会超过n,这样的结果事实上已经告诉我们此时可以直接结束算法了,即:
k = k + m * (n - i) ;
i = n;
结束。
另外对于m = 1的情况可以单独讨论:
当k == 1时,最终结果就是n;
当k != 1时,最终结果就是(k + n - 1) % n。

 1 var
 2     n,m                                     :int64;
 3
 4 function ysf(n,m,k:int64):int64;
 5 var
 6     i,j,x                                    :int64;
 7 begin
 8     if m=1 then
 9     begin
10         if (k=1) then k:=n else k:=(k+n-1) mod n;
11     end else
12     begin
13         i:=1;
14         while i<=n do
15         begin
16             if (k+m<i) then
17             begin
18                 x:=(i-k+1) div (m-1) -1;
19                 if (i+x<n) then
20                 begin
21                     i:=i+x;
22                     k:=(k+m*x);
23                 end else
24                 begin
25                     k:=k+m*(n-i);
26                     i:=n;
27                 end;
28             end;
29             k:=(k+m-1) mod i+1;
30             inc(i);
31         end;
32     end;
33     exit(k);
34 end;
35
36 begin
37     read(n,m);
38     writeln(ysf(n,m,0));
39 end.
时间: 2024-12-15 07:15:18

约瑟夫环问题的优化及终极优化的相关文章

Citrix XenDesktop Studio 7.x & StoreFront控制台打开速度慢终极优化

部署过CitrixXenDesktop的同学们都知道,Studio控制台与StoreFront控制台某些时候打开慢的那叫一个纠结啊,尤其是等待排除某些问题的时候,等待是很煎熬的,好了废话少说,下面我来给大家说一下Studio的优化,不是很快吧,起码比不优化能节省上很长时间. 这些优化设置建议在部署Citrix环境的时候做到模板中,这样就避免了出来后一台一台修改 优化步骤 1. IE设置 Citrix XenDesktop现在也开始走我大微软的路子,默认内部的很多通讯采用Powershell,WS

WordPress SEO ? WordPress网站终极优化指南

原文地址:http://www.eastdesign.net/wordpress-seo/ 最新消息,东方设计学院 WordPress SEO 系列视频教程正在持续更新中,目前为了不至于让视频传播过于泛滥,设置了登陆权限,有兴趣查看的用户可以简单填写一个索取测试账号的表单,提交一份表单给我们,我们将尽快回复测试账号登陆密码,视频教程地址:http://www.eastdesign.net/wordpress-seo-tutorial/ WordPress网站终极优化指南 WordPress 是一

Android性能优化【终极篇】

1.http用gzip压缩,设置连接超时时间和响应超时时间 http请求按照业务需求,分为是否可以缓存和不可缓存,那么在无网络的环境中,仍然通过缓存的httpresponse浏览部分数据,实现离线阅读. 2.listview 性能优化 1).复用convertView 在getItemView中,判断convertView是否为空,如果不为空,可复用.如果couvertview中的view需要添加listerner,代码一定要在if(convertView==null){}之外. 2).异步加载

poj 2886 Who Gets the Most Candies?(线段树+约瑟夫环+反素数)

Who Gets the Most Candies? Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 9934   Accepted: 3050 Case Time Limit: 2000MS Description N children are sitting in a circle to play a game. The children are numbered from 1 to N in clockwise o

HDU 3089 (快速约瑟夫环)

Josephus again Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 652    Accepted Submission(s): 181 Problem Description In our Jesephus game, we start with n people numbered 1 to n around a circle

POJ 3517 And Then There Was One(约瑟夫环-递推or模拟)

POJ 3517 题目: n  k m 数字1到n成环,先叉数字m,往下数k个,直到最后只有一个数字,输出它. 链表模拟: #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<cmath> #include<vector> #incl

1074 约瑟夫环 V2

1074 约瑟夫环 V2 基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题 收藏 关注 N个人坐成一个圆环(编号为1 - N),从第1个人开始报数,数到K的人出列,后面的人重新从1开始报数.问最后剩下的人的编号. 例如:N = 3,K = 2.2号先出列,然后是1号,最后剩下的是3号. Input 2个数N和K,表示N个人,数到K出列.(2 <= N <= 10^18, 2 <= K <= 1000) Output 最后剩下的人的编号 Input

趣味算法--约瑟夫环问题

问题描述 已知n个人(以编号1,2,3,...,n分别表示)围坐在一张圆桌上.指定编号为k的人开始从1报数,数到m的那个人出列:出列那个人的下一位又从1开始报数,数到m的那个人出列:以此规则重复下去,直到圆桌上的人全部出列. 分析解决 解决方法主要有逻辑分析.数学分析法. 逻辑分析:就是按照游戏规则一个个报数,报到m的人出局,结构层次简单清晰明了.这种方式实现主要采用顺序表实现 数学分析:采用数学方式归纳统计分析出每次出局人的规律,直接得出每次出局的人,然后以代码实现.这种方法需要较强的数学分析

约瑟夫环以及其变种集合

最近在CF上补题,补到了一道关于约瑟夫环的题目(听都没听过,原谅我太菜) 就去好好学了一下,不过一般的题目应该是不会让你模拟过的,所以这次就做了一个约瑟夫环公式法变形的集合. 关于约瑟夫环的基础讲解,我个人认为最好的就是这篇了. 首先是最原始的约瑟夫环的题目: https://vjudge.net/problem/51Nod-1073(小数据规模) #include <bits/stdc++.h> using namespace std; int main() { ios::sync_with