Joseph Problem(解约瑟夫问题)

  今天在一个OJ上做了一个Joseph Problem(解约瑟夫问题)的题,题目不难,直接用循环链表模拟实际操作即可完成,但是用此种方法的时间太长,超时,所以我就用了一个大家对这类问题比较常用的解法——数学方法。

问题再现:

题目内容:
实作Joseph problem.
假设一开始有N个人,编号1~N,
按照顺序以顺时针围成一个圆圈。
游戏开始时,编号1的人拿刀。
之后每一轮刀子会被往下传M个人,
而当轮最后拿到刀子的人会将他的下一个人杀掉,
杀完后刀子会再传给被杀的下一个人。
这样一轮就算结束。
游戏会进行许多轮,直到只剩下最后一个人。
范例1:N=5, M=2
第一轮:刀子传给3号,4号被杀,刀子再传给5号 (1 2 3 5)
第二轮:刀子传给2号,3号被杀,刀子再传给5号 (1 2 5)
第三轮:刀子传给2号,5号被杀,刀子再传给1号 (1 2)
第四轮:刀子传给1号,2号被杀,最后1号存活。
范例2:N=4, M=3
第一轮:刀子传给4号,1号被杀,刀子再传给2号 (2 3 4)
第二轮:刀子传给2号,3号被杀,刀子再传给4号 (2 4)
第三轮:刀子传给2号,4号被杀,最后2号存活。
输入格式:
输入第一行为一个数字T,代表测资的笔数。
接下来会有T笔测资,每一笔测资一行,
会有两个数字N,M,数字间以空格区隔。
数字范围:
T < 1000
0 < N <= 1000
0 < M <= 1000
输出格式:
输出一行数字,将每笔测资最后存活下来的人的编号加总。
输入样例:
3
5 2
4 3
8 4
输出样例:
4
时间限制:1000ms内存限制:32000kb

算法实现:

  • 循环链表(真实模拟)算法

第一点想到的实现算法就是完全模拟问题中的方法进行算法设计,代码如下:

#include <stdio.h>int arrQ[1000]; //循环队列,此处用固定值 
int Qcount, head, tail; //队列操作 void add(int x, int size){if(Qcount == 0){arrQ[0] = x;}else{tail = (tail + 1) % size;arrQ[tail] = x;}Qcount ++;
}void del(int size){head = (head + 1) % size;Qcount --;
}int main(){int T, N, M, sum = 0;int i, j, k, tmp;scanf("%d", &T);for(i = 0; i < T; i ++){scanf("%d", &N);scanf("%d", &M);Qcount = head = tail = 0;for(j = 0; j < N; j ++){ //初始队列 add(j + 1, N);}while(Qcount != 1){ //直到剩下最后一个人 for(k = 0; k <= M; k ++){ //根据题意 执行M+1次操作 tmp = arrQ[head];del(N);add(tmp, N);}del(N);}sum += arrQ[head];	}printf("%d", sum);return 0;
}
此算法虽然很容易理解,但是时间复杂度是O(nm),执行大队列时会超时。

  • 数学推导进行求解

这里先拿一个经典的例子进行说明。

问题:有n个人站成环 从1开始报数,报k的人出列,之后下一个人报1,问最后存在的是谁?


这里设n = 11,k = 3。下面将处理的所有过程写下来。

最后存在的是7。

这里可以用 f(n, k)来描述每一轮的操作,n是当前队列中的人数,k是出列的人,f(n,k) = (f(n - 1,k) + k) % n,下面来实现。

最底端是 f(1,k)  f(1,k) = 0 就是说只有一个人的时候存在者的下标是0,编号是7

向上,f(2,k) = (f(1,k) + k) % n  =  f(2,3)=(f(1,3) + 3) % 2 = 3 % 2 = 1,在只剩两个人时,存在者在这一轮数组中的下标位置是1(下标位置为1 编号是7 )

向上,f(3,3) = (f(2,3) + 3) % 3 = 4 % 3 = 1,在只剩三个人时 在存者在这一轮数组中的下标位置是1 (下标位置为1 编号是7)
向上,f(4,3) = (f(3,3) + 3) % 4 = 4 % 4 = 0
……

……

最后,f(11,3) = (f(10,3) + 3) % 11 = 6 % 11 = 6  (看看上面的表格第一行 下标位置为6 编号是7 )

在只剩三个人时 幸存者在这一轮数组中的下标位置是0  (看看上面的表格 下标位置为0 编号是7 )

通过上述很容易写出程序来:

int fn(int n,int k){int s = 0; //最后存在者的下标 for(int i=2;i<=n;i++)    {s = (s + k) % i;}return s + 1; //因为是从数组下标是从0开始的,所以这里要加1 
}

好了,经典问题说完后,来看一下我们这个题,把这种数学推导出来的公式移植到程序中,如下:

#include <stdio.h>int main() {int N, M, T, sum = 0;int i, s;scanf("%d", &T);while(T--) {scanf("%d %d", &N, &M);s = 0;for(i = 2; i <= N; i ++){s = (s + M + 2) % i; //因为题目中要求是从当前位置的M个位置的下一个人出列,所以这里要加2 }sum += s+1;}printf ("%d", sum);return 0;
}

这里的时间复杂度是O(n),所以完胜。


博客名称:王乐平博客
博客地址:http://blog.lepingde.com
CSDN博客地址:http://blog.csdn.net/lecepin


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/401739.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux下mono的安装与卸载

我很遗憾的告诉你&#xff0c;这里没有安装&#xff0c;为什么标题里加入安装俩字呢&#xff0c;因为如果不加的话你会搜到这篇文章吗&#xff1f;哈哈&#xff01;别气馁&#xff0c;这里会给你些安装的tips&#xff01; 源码安装&#xff0c;git安装&#xff1a;建议安装路径…

繁体简体转换器 v 1.0

软件截图 软件说明 软件名称&#xff1a;繁体简体转换器 软件版本&#xff1a; 1.0 开发语言&#xff1a;易语言 软件说明&#xff1a;本软件主要是用于繁体中文转换为简体中文的工具&#xff0c;如果你想把转换后的文本用于MarkDown中&#xff0c;可以勾选“HTML转义”复选…

C#实现Combobox自动匹配字符

不多说了,如图,应客户要求,下拉框中需要自动匹配字符,可能有些人一早就对此很熟,但相对于我还是首次使用,还是花了一点时间,现记录下来,也希望能帮助大家更好的理解. 首先要设定Combobox的DropDownStyle属性为DropDown,而不是DropDownList.然后设定匹配数据源,有两种方法 第一种…

按键 使用WinHttp实现POST方式用户模拟登录网站

引言 这篇文章是我以前在一个论坛里写的&#xff0c;今天把这篇文章转移到这里。 文章主要介绍了如何模拟一个网站的登录。 这里使用的辅助工具是按键精灵&#xff0c;编程语言类似于VB。 实现步骤 第一步&#xff0c;获取登录地址 打开登录界面&#xff1a; 打开调试工…

华硕 RT-AC54U路由器固件功能说明

引言 华硕 RT-AC54U这款路由器固件&#xff0c;界面做的很不错&#xff08;起码比OpenWrt要好看&#xff09;&#xff0c;功能也比较强悍&#xff0c;但是对于刚入手这个固件的用户可能会对此固件的一些很好用的功能无从下手&#xff0c;所以这里我就写下了这个文章。 固件亮…

HTML5中类jQuery选择器querySelector的使用

为什么80%的码农都做不了架构师&#xff1f;>>> 简介 HTML5向Web API新引入了document.querySelector以及document.querySelectorAll两个方法用来更方便地从DOM选取元素&#xff0c;功能类似于jQuery的选择器。这使得在编写原生JavaScript代码时方便了许多。 用法 …

Find the Kth number(找第K大数)

题目再现 题目内容&#xff1a; 给定N个排序好的序列&#xff0c;每个序列内有M个数字。因此我们总共有N*M个数字&#xff0c;编号为1~N*M。 将N*M个数字排序后输出第K个数字是多少。Hint : 直接将N*M个数字做排序会超过时间限制。 Hint : 每次花O(N)的时间找一个数字&#xf…

Species Tree(HashTable实现)

题目再现 题目内容&#xff1a; 给定一个物种演化图&#xff0c; 关系的表示方式如下&#xff1a; x y : 表示x为y的先祖。 一个物种只会有一个先祖&#xff0c; 一个先祖可以有很多个演化出来的物种&#xff0c; 请你找出每个问题询问物种的祖父物种(先祖的先祖)&#xff0c;…

Adjacent Node Sum(邻接表处理)

题目再现 题目内容&#xff1a; 给定一个节点有权重的图&#xff0c; 请你计算与一个节点相邻的所有节点的权重和。 节点编号为1~N。 每个节点的编号即为他的权重。输入格式: 只有一组测资。 第一行有三个数字&#xff0c;N、M、Q。 N表示这张图有多少节点&#xff0c; M表示这…

Maze(BFS处理)

题目再现 题目内容&#xff1a; 给你一个迷宫&#xff0c; S为起点&#xff0c;E为终点。 请你找出走出迷宫所需要花费的最短步数。 你只能往上下左右四个方向移动。输入格式: 第一行有一个数字T&#xff0c;代表有T组测资。 每组测资的第一行有两个数字R、C&#xff0c; 代表…

Lotto(DFS处理)

题目再现 题目内容&#xff1a; 给定N个数字&#xff0c;再从中选定M个数字出来。 将每一种组合内的数字由小到大排列之后&#xff0c; 将所有组合按照字典序排列&#xff0c; 请你找出第X组的第Y个数字。 给定的数字为1~N。 范例1 (N,M,X,Y) (5,2,8,2) 所有组合按顺序排列为…

2016第七届蓝桥杯省赛C/C++ B组试题解析整理

引言 今天是蓝桥杯省赛举办的日子&#xff0c;是一个很激动人心的时刻&#xff0c;也是我第一次参加蓝桥杯&#xff0c;从上午9点到下午1点&#xff0c;做题时间历经4个小时&#xff0c;想想就过瘾。 下面整理一下这次比赛的题目。 *注&#xff1a;此处为了省事儿&#xff…

Linux 小知识翻译 - 「邮件服务器」

这次聊聊「邮件服务器」。 邮件服务器上通常会运行2个服务端软件&#xff0c;「SMTP服务器」和「POP服务器或者IMAP服务器」。 这2个东西&#xff0c;也许使用邮件客户端的人立马就明白了。因为设置邮件客户端的时候&#xff0c;需要指定「发信服务器」和「收信服务器」。 这2个…

终极结束进程方法API

引言 最近在机房里上课的时候&#xff0c;学生的电脑上都安装了相应的学生端软件&#xff0c;而这些软件并没法正常关闭&#xff0c;用任务管理器也无法关闭&#xff0c;下面我说一下如何用Windows API对这类顽固程序进行终结。 福利方法 由于相关方面的规定&#xff0c;这里…

Android Fragments 详细使用

2019独角兽企业重金招聘Python工程师标准>>> Fragments 诞生初衷 自从Android 3.0中引入fragments 的概念,根据词海的翻译可以译为:碎片、片段。其上的是为了解决不同屏幕分辩率的动态和灵活UI设计。大屏幕如平板小屏幕如手机&#xff0c;平板电脑的设计使得其有更多…

安卓UI适配限定符

引言 对于程序在不同尺寸的Android机器上运行&#xff0c;对UI的适用性造成了额外的开销&#xff0c;不过限定符的出现&#xff0c;很方便的解决了这个问题。通过创建限定符相关的文件夹来解决资源的加载。 限定符用处 限定符(mdpi,tvdpi,hdpi)可以帮助我们判断屏幕密度 限定…

docker install on centos 6.x

2019独角兽企业重金招聘Python工程师标准>>> 参考文档:http://docs.docker.com/installation/centos/ 安装epel源 wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo 安装docker服务端 yum install docker-io 启动docker /etc/init.…

安卓活动(Activity)和碎片(Fragment)的生命周期

引言 对于安卓中生命周期的过程以及相应的事件的了解是非常重要的。 活动&#xff08;Activity&#xff09;的生命周期 Activity 类中定义了七个事件回调方法&#xff0c;与Activity生命周期的每一个环节对应。 1. onCreate() 这个方法你已经看到过很多次了&#xff0c;每个…

又开始写博了

2019独角兽企业重金招聘Python工程师标准>>> 因为太多东西需要记录&#xff0c;所以重新开博。脚印一把 转载于:https://my.oschina.net/junfrank/blog/286348

Android 代码实现查看SQLite数据库中的表

前言 以前写PHP的时候&#xff0c;内置了print_r()和var_dump()两个函数用于打印输出任意类型的数据内部结构&#xff0c;现在做Android的开发&#xff0c;发现并没有这种类似的函数&#xff0c;对于数据库的查看很不方便&#xff0c;于是就写了一下查看数据库表的方法代码。 …