HDU1443(约瑟夫环的应用)
来源:互联网 发布:linux配置samba服务器 编辑:程序博客网 时间:2024/06/06 02:14
题目链接
题目描述:
Joseph
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 2209 Accepted Submission(s): 1342
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.
340
530
题意:
这道题是典型的约瑟夫环应用的问题。题目说的是有k个好人和k个坏蛋围坐在圆桌旁边,好人的编号是前k个,而坏蛋的编号是紧接着好人的后k个,然后就是与约瑟夫环问题相似的情况了,从1开始报数,报至m的人出列,然后从下一个人开始继续从1开始报数,并按此规律循环报数下去。而题目要求确定最小的m值,使得前k个出列的总是这k个坏蛋,即是所有坏蛋总是在好人之前出列。
解析:
对于这种确定最小值的题目,我们可以先看一下k的取值范围,0 < k < 14,咋一看,觉得k值很小,但是呢,这道题却是需要一点数学技巧的。刚开始的时候可能会没有头绪,所以我们可以从第一次报数开始一次次的分析,从而寻找出一般规律。
为了方便起见,我们设编号从0开始,这样的话报到m-1的人出列(这样做不用特判最后一个数的情况),从而简化分析过程。
一开始的时候,所有人的按照编号顺序的序列为:
0,1,2,3...k-2,k-1...2k-2,2k-1
由于题目要求是所有坏蛋总是在好人之前出列,所以我们可以将好人圈定起来,如果出列的人在此范围之内,说明就与题意不符。
在这里,我们可以设start_num和end_num两个变量来记录好人编号的起止,所以一开始的时候可将这两数初始化为:
int start_num = 0,end_num = k-1;
而第一次出列的人的序号为(m-1)%n(n表示当前序列总人数),为了方便,我们可以设一个变量q来记录该次出列的人的序号,即
q = (m-1)%n。当第一个人出列之后,从该人的下一个人又是按照相同的方式报数,因此呢,下一次报数的过程的编号序列为:
q+1,q+2,q+3...2k - 1,0,1,2...q-1
而由于这一过程依旧是从0开始报数,那么该过程中的编号序列中每个人报数序列依旧为:
0,1,2,3....2k-3,2k-2
那么这样的话,报数序列与编号序列对应起来:
0 ---> q +1
1 ---> q + 2
...
2k-3 ---> q - 2
2k-2 ---> q - 1
那么依旧按照上述处理过程,报数报到m-1的人出列,后面的过程也是与这两次的一模一样,所以我们在第一次记录了好人编号的起止之后,在一次出列处理之后,好人的相对编号发生了改变,但是好人与好人之间的"相对顺序“还是不变的,因此我们在第二次处理出列的时候,可以将其看成n-1阶的约瑟夫环问题,那么出列的人报的数还是(m-1)%n(n表示当前序列总人数),但是好人的起始编号却发生了改变,如果我们要把第二次处理出列的过程看成n-1阶的约瑟夫环的问题的话,相当于把所有人的编号都减去(q+1),这样的话,大家的编号又是从0开始了,这是这时候人数减1了。
所以这时候好人起止编号更新为:
start_num = start_num - (q + 1)
end_num = end_num - (q + 1)
而q = (m-1)%n
证明:(x-a)%n = (x-a+n)%n
右边等于((x-a)%n+n%n)%n = (x-a)%n
等于左边,因此得证。
因此则有(考虑到可能最后的差小于0的情况,因此需加上总人数再取余):
start_num = (start_num - (m%n)+ n)% n
end_num = (end_num - (m%n)+ n)% n;
而再往后继续递推,会发现其实后面报数出列的过程与前面的过程是一模一样的,这是将问题的维数降低(即总人数减少)。因此我们可以利用一个for循环,不断更新出列的人的编号,好人的起止编号即可。
完整代码实现:
#include<cstdio>#include<algorithm>bool Judge(int k,int m){ //k表示好孩子截止的序号,m表示报到的号数 int start_num = 0,end_num = k-1; int kill_num; for(int i = 2*k;i>k;--i){ kill_num = (m-1)%i; //i表示当前序列人数 if(kill_num>=start_num&&kill_num<=end_num){ return false; } start_num = ((start_num-m)%i+i)%i; end_num = ((end_num-m)%i+i)%i; } return true;}int main(){ int ans[14]; for(int i = 1;i<14;++i) for(int j = 1;;++j){ if(Judge(i,j)){ ans[i] = j; break; } } int q; while(scanf("%d",&q)==1&&q){ printf("%d\n",ans[q]); } return 0;}
约瑟夫环是经典问题,要多回顾。
如有错误,还请指正,O(∩_∩)O谢谢
- HDU1443(约瑟夫环的应用)
- pku1012==hdu1443约瑟夫环问题
- hdu1443(约瑟夫环游戏的原理 用链表过的)
- hdu1443
- hdu1443
- hdu1443
- hdu1443
- HDU1443
- HDOJ 1443 约瑟夫环的最新应用
- 约瑟夫环的问题与应用(JAVA)
- 约瑟夫环应用问题
- Hdu1443(Joseph)巧妙的提交
- 链表应用--约瑟夫环
- 循环链表的应用_约瑟夫环
- 队列的简单应用-杨辉三角和约瑟夫环
- 数据结构 循环链表的应用:约瑟夫环问题
- 循环链表的应用——约瑟夫环
- 约瑟夫环问题 【循环链表的应用】
- [数位dp+二分] LightOJ 1105 - Fi Binary Number
- Jenkins进阶系列之——16一个完整的JENKINS下的ANT BUILD.XML文件
- 第四周项目5-用递归方法求解(1)
- c++四种类型转换
- Git的常用命令
- HDU1443(约瑟夫环的应用)
- 快速排序详细解释
- 开源软件收集帖
- JS事件模型
- 用标尺法快速找到单链表的中间结点
- js积累
- 【HDU 5646】DZY Loves Partition
- 关于c++中stack、queue和priority_queue的介绍
- 用javascript实现sliding door 的效果