华为机试 之 joseph环
一:首先科普一下约瑟夫问题的数学方法
(1) 不管是用list实现还是用vector实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比較烦,并且时间复杂度高达O(nm),当n,m很大(比如上百万,上千万)的时候,差点儿是没有办法在短时间内出结果的。我们注意到原问题不过要求出最后的胜利者的序号,而不是要读者模拟整个过程。因此假设要追求效率,就要打破常规,实施一点数学策略。
(2) 为了讨论方便,先把问题略微改变一下,并不影响原意: 问题描写叙述:n个人(编号0~(n-1)),从0開始报数,报到(m-1)的退出,剩下的人继续从0開始报数。求胜利者的编号。 我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人開始): k k+1 k+2 ... n-2, n-1, 0, 1, 2, ... k-2 而且从k開始报0。 如今我们把他们的编号做一下转换: k --> 0
k+1 --> 1 k+2 --> 2 ... ... k-2 --> n-2 k-1 --> n-1 变换后就完全然全成为了(n-1)个人报数的子问题。
(3)假如我们知道这个子问题的解:比如x是终于的胜利者,那么依据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!变回去的公式非常easy,相信大家都能够推出来:x'=(x+k)%n 怎样知道(n-1)个人报数的问题的解?对,仅仅要知道(n-2)个人的解即可了。(n-2)个人的解呢?当然是先求(n-3)的情况 ---- 这显然就是一个倒推问题!好了,思路出来了,以下写递推公式:
令f[i]表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是f[n] ;递推公式 ; f[1]=0; f[i]=(f[i-1]+m)%i; (i>1)
有了这个公式,我们要做的就是从1-n顺序算出f[i]的数值,最后结果是f[n]。由于实际生活中编号总是从1開始,我们输出f[n]+1 由于是逐级递推,不须要保存每一个f[i],程序也是异常简单。
二:原题再现:
(1)The Joseph's problem is notoriously known. For those who are not familiar with the original problem: from among n people, numbered 1, 2, . . ., n, standing in circle every mth is
going to be executed and only the life of the last remaining person will be saved. Joseph was smart enough to choose the position of the last remaining person, thus saving his life to give us the message about the incident. For example when n = 6 and m = 5
then the people will be executed in the order 5, 4, 6, 2, 3 and 1 will be saved.
Suppose that there are k good guys and k bad guys. In the circle the first k are good guys and the last k bad guys. You have to determine such minimal m that all the bad guys
will be executed before the first good guy.
(2)分析:本题是约瑟夫环变形 先引入Joseph递推公式,设有n个人(0,...,n-1),数m,则第i轮出局的人为f(i)=(f(i-1)+m-1)%(n-i+1),f(0)=0; f(i) 表示当前子序列中要退出的那个人(当前序列编号为0~(n-i));
拿个样例说:K=4,M=30;
f(0)=0;
f(1)=(f(0)+30-1)%8=5; 序列(0,1,2,3,4,5,6,7)中的5
f(2)=(f(1)+30-1)%7=6; 序列(0,1,2,3,4,6,7)中的7
f(3)=(f(2)+30-1)%6=5; 序列(0,1,2,3,4,6)中的6
f(4)=(f(3)+30-1)%5=4; 序列(0,1,2,3,4)中的4
........
根据题意,前K个退出的人必然是后K个人,所以仅仅要前k轮中仅仅要有一次f(i)<k则此m不符合题意。
接下来说说m的取值范围:我们考察一下仅仅剩下k+1个人时候情况,即坏人另一个未被处决,那么在这一轮中结束位置必然在最后一个坏人,那么開始位置在哪呢?这就须要找K+2个人的结束位置,然而K+2个人的结束位置必然是第K+2个人或者第K+1个人,这样就出现两种顺序情况:GGGG.....GGGXB 或 GGGG......GGGBX (X表示有K+2个人的那一轮退出的人)所以有K+1个人的那一轮的開始位置有两种可能即第一个位置或K+1的那个位置,限定m有两种可能:t(k+1) 或 t(k+1)+1; t>=1;
若遍历每个m必然超时,避免超时则须要打表和限制m的范围。
(3) 代码例如以下:
using namespace std;
const int MAX_SIZE = 14; int main(void)
{
int joseph[MAX_SIZE]={0}; //打表,保存各个k值相应的m值 int k;
int i;
while(cin>>k)
{
if(0 == k)
break;
if(joseph[k])// 此k值已经求过直接打印,并下一次循环
{
cout<<joseph[k]<<endl;
continue;
} int n=2*k; //总人数
int ans[30]={0}; //第i轮杀掉 相应当前轮的编号为ans[i]的人
//PS:每一轮都以报数为“1”的人開始又一次编号
// 比如ans[1] = 3 表示第一次把下标为3的人杀掉(事实上是第四个人)
int m=k+1; //所求的最少的报数,从k+1開始,由于
for(i=1;i<=k;i++)
{
ans[i] = (ans[i-1]+m-1)%(n-i+1);
//cout << ans[i] << ",";// 杀人的原始数组的下标,也相当于erase过程,由于要迁移
//假设应用vector的vec[i],vec.erase(iter)就能够实现杀人顺序
if(ans[i] < k)// 不符合杀人条件
{
i = 0;
m++;// m加一,从i=1再次杀人
}
}
joseph[k] = m;
cout << joseph[k] << endl;
}
return 0;
}//poj 1012
三:问题延伸:(更简单的问题)
接下来每行输入一个小孩的名字(人名不超过15个字符)
最后一行输入W,S (W < N),用逗号","间隔
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int MAX_SIZE = 20; int main()
{
int n,w,s;
int i,cp;
char str[MAX_SIZE];
vector<string> vec;
scanf("%d",&n);
for(i=0;i<n;i++)
{
cin >> str;
vec.push_back(str);
}
scanf("%d,%d",&w,&s);
vector<string>::iterator iter;
cp = 1;
for(iter=vec.begin()+w-1; vec.begin()!=vec.end();)
{
cp++;
if(iter == vec.end())
iter = vec.begin();
if(cp<=s)
{
iter++;
}
else
{
cout << *iter << endl;
iter = vec.erase(iter);
//iter++;// 由于删除iter,自己主动指向下一个元素的;
cp = 1;
}
} return 0;
}//poj 3750
*/ #include <iostream>
#include <cstdio>
#include <cstring>
#include <list>
using namespace std;
const int MAX_SIZE = 20; int main()
{
int n,w,s;
int i,cp;
char str[MAX_SIZE];
list<string> lists;
scanf("%d",&n);
for(i=0;i<n;i++)
{
cin >> str;
lists.push_back(str);
}
scanf("%d,%d",&w,&s);
list<string>::iterator iter;
iter = lists.begin();
while(w>1)
{
iter++;
w--;
}
cp = 1;
for(; lists.size()!=0;)
{
cp++;
if(iter == lists.end())
iter = lists.begin();
if(cp<=s)
{
iter++;
}
else
{
cout << *iter << endl;
iter = lists.erase(iter);// 由于删除iter,自己主动返回下一个元素的,vector也是一样;否则ter成为野指针
cp = 1;
}
}
return 0;
}//poj 3750
华为机试 之 joseph环的更多相关文章
- 2014华为机试西安地区B组试题
2014华为机试西安地区B组试题 题目一.亮着点灯的盏数 一条长廊里依次装有n(1≤n≤65535)盏电灯,从头到尾编号1.2.3.-n-1.n.每盏电灯由一个拉线开关控制.開始,电灯所有关着. 有n ...
- 华为机试001:字符串最后一个单词的长度(华为OJ001)
华为机试 字符串最后一个单词的长度 计算字符串最后一个单词的长度,单词以空格隔开. 提交网址: http://www.nowcoder.com/practice/8c949ea5f36f422594b ...
- 2014华为机试西安地区A组试题
2014华为机试西安地区A组试题 题目一.分苹果 M个同样苹果放到N个同样篮子里有多少种放法,同意有篮子不放. 1<=M<=10.1<=N<=10 比如5个苹果三个篮子,3,1 ...
- 华为机试ACM(字符组合问题)
今晚做了华为的机试,3道ACM题,最后一道是实现从M个不同字符中任取N个字符的所有组合. eg: input:ABC 2 output:AB AC BC 第一个输入为字符串,第二个输入为组合的字符个数 ...
- 华为机试正式版(西安c/c++/java),今天下午去机试的题目,新奇出炉了!
下面题目都是回顾的.题目都非常easy, 大家有些基础就能够參加!(语言能够是c/c++.也能够是java的) 题目一(60分): 字符串操作. 将小写转换成大写, 将大写转化为小写, 数字的不做转换 ...
- 华为机试_字符串识别_Vector的使用;
第一题:拼音转数字输入是一个只包含拼音的字符串,请输出对应的数字序列.转换关系如下:描述: 拼音 yi er san si wu liu qi ba jiu ...
- 输入一个字符串,去掉重复的字符,并按ASCII值排序-华为机试
import java.util.Scanner; //输入字符串,去掉重复的字符,并按ASSIC码值排序 public class quChong { public static void main ...
- 2015华为机试——数字基root
题目描写叙述: 求整数的Root:给定正整数,求每位数字之和;假设和不是一位数,则反复; 输入:输入随意一个或多个整数 输出:输出各位数字之和,直到和为个位数为止(输入异常,则返回-1),多行,每行相 ...
- 华为机试-iNOC产品部-杨辉三角的变形
题目描述 1 1 1 1 1 2 3 2 1 1 3 6 7 6 3 11 4 10 16 19 16 10 4 1以上三角形的数阵,第一行只有一个数1,以下每行的每个数,是恰好是它上面的数,左上角数 ...
随机推荐
- akka.net与微软分布式框架Orleans
微软分布式框架Orleans开源了 开源地址: https://github.com/dotnet/orleans 昨天编译了一下,这个最新的Orleans安装程序(用github源码编译的) 下载地 ...
- 从"分层二进制输出"至"解决二进制树深度"总结
本文研究的摘要,欢迎转载,但请注明出处:http://write.blog.csdn.net/postedit/41964669 近期在刷LettCode上的算法题,发现好多题目的解题思路大体是一致的 ...
- Mongodb 之insert瞬时完成,测试数据---飞天博客
这几天看mongdb官方网站,然后将执行数据.突然,我发现,该数据确实很强大,在这里说话数据.我用普通的pc机,amd双核 2.7GHz,4G内存,当然,当系统不只是在测试作为数据库server的.同 ...
- mysql声明摘要
前一段时间,和学生参加该项目的最终完成,主要的项目是做一个报告,它涉及到很多sql声明,因此,采取下一个汇总. 一.基金会 1.数据库相关的命令 a>.创建数据库 CREATE DATABASE ...
- SAP ABAP规划 SY-REPID与SY-CPROG差额
首先.它的两个解释 sy-repid is the name of the current program. "当前程序的程序名 ...
- ajaxFileUpload+struts2多文件上传(动态添加文件上传框)
上一篇文章http://blog.csdn.net/itmyhome1990/article/details/36396291介绍了ajaxfileupload实现多文件上传, 但仅仅是固定的文件个数 ...
- Hadoop处理HDF文件
1.前言 HDF文件是遥感应用中一种常见的数据格式,因为其高度结构化的特点,笔者曾被怎样使用Hadoop处理HDF文件这个问题困扰过相当长的一段时间.于是Google各种解决方式,但都没有找到一种理想 ...
- Jeditable 点击编辑文字插件
Jeditable - jQuery就地编辑插件使用 jeditable是一个jquery插件,它的优点是可以就地编辑,并且提交到服务器处理,是一个不可多得的就地编辑插件.(注: 就地编辑,也有称 ...
- tomcatserver乱码问题,tomcat与数据库之间的编码统一转换
在tomcat文件夹的conf文件夹下,改动server.xml文件,在以下截图中的位置加上URIEncoding="UTF-8"则表示tomcat编码转换为utf-8风格, 一般 ...
- 使用JS意识到自己主动提交表单
今天将需要chat集成到客户的网站上去,注册用户链接登录这个网站后点击实现网站直接登录chat向上.我不停chat原来的登录界面,采纳JS当页面跳转技术,随着时间的推移自己主动填写表格.自己主动提交表 ...