Roman Roulette(约瑟夫环模拟)

Roman Roulette

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 286    Accepted Submission(s): 105

Problem Description

The historian Flavius Josephus relates how, in the Romano-Jewish conflict of 67 A.D., the Romans took the town of Jotapata which he was commanding. Escaping, Jospehus found himself trapped in a cave with 40 companions. The Romans discovered his whereabouts and invited him to surrender, but his companions refused to allow him to do so. He therefore suggested that they kill each other, one by one, the order to be decided by lot. Tradition has it that the means for effecting the lot was to stand in a circle, and, beginning at some point, count round, every third person being killed in turn. The sole survivor of this process was Josephus, who then surrendered to the Romans. Which begs the question: had Josephus previously practised quietly with 41 stones in a dark corner, or had he calculated mathematically that he should adopt the 31st position in order to survive?

Having read an account of this gruesome event you become obsessed with the fear that you will find yourself in a similar situation at some time in the future. In order to prepare yourself for such an eventuality you decide to write a program to run on your hand-held PC which will determine the position that the counting process should start in order to ensure that you will be the sole survivor.

In particular, your program should be able to handle the following variation of the processes described by Josephus. n > 0 people are initially arranged in a circle, facing inwards, and numbered from 1 to n. The numbering from 1 to n proceeds consecutively in a clockwise direction. Your allocated number is 1. Starting with person number i, counting starts in a clockwise direction, until we get to person number k (k > 0), who is promptly killed. We then proceed to count a further k people in a clockwise direction, starting with the person immediately to the left of the victim. The person number k so selected has the job of burying the victim, and then returning to the position in the circle that the victim had previously occupied. Counting then proceeeds from the person to his immediate left, with the kth person being killed, and so on, until only one person remains.

For example, when n = 5, and k = 2, and i = 1, the order of execution is 2, 5, 3, and 1. The survivor is 4.

Input

Your program must read input lines containing values for n and k (in that order), and for each input line output the number of the person with which the counting should begin in order to ensure that you are the sole survivor. For example, in the above case the safe starting position is 3. Input will be terminated by a line containing values of 0 for n and k.

Your program may assume a maximum of 100 people taking part in this event.

Sample Input

1 1
1 5
0 0

Sample Output

1 1

题解:

历史学家弗拉维·约瑟夫曾讲述过这样的故事:在公元前67年的罗马犹太战争中,罗马攻下了他掌权的城市。随后,他与另外40个反抗战士一起逃到了一个山洞中而被困在里面。罗马人发现了他的下落并劝他投降,但他的战士们拒绝投降。于是他提议互相杀死对方,一个接一个,顺序由大家决定。有一种传统的方式,即为了公平起见所有人都站成一个环,从某一点开始,循环计数,每隔两个活着的人就杀掉一个。最后只有约瑟夫幸存了下来,投降了罗马。问题来了,约瑟夫如何知道一开始站第31位才会幸存到最后呢?是不是趁着洞穴黑暗大家没注意,悄悄地用41个石子演练过了?还是他用数学方法计算出了这个位置?

在仔细读过这个故事由来后,你逐渐克服了恐惧心理,不再害怕将来这种事会发生到你的头上。但为了应对这种类似的情况,你准备为你的手机写一个程序,以便快速的计算这个过程并确保你能站到最后幸存的位置上。

类似于约瑟夫所述的问题,你的程序需要处理如下改编过的问题。最初n(n > 0)个人面朝内围成一个环,并依次按顺时针编号1到n。你的编号为1,第一个轮到的人编号为i,同样顺时针方向开始计数,直到第k(k > 0)个人把他杀掉。然后再从下一个还活着的人开始向后数到第k个人,由这个人来把刚才杀掉的人埋葬,并站到被杀的人的位置上。然后再从他左面第一个还活着的人开始计数,杀掉第k个人,以此类推,直到只有一个人还活着。

比方说,n = 5,k = 2,i = 1,被杀的顺序应为:2、5、3和1。4幸存。

分析

类似于经典的约瑟夫环问题,这类问题都是可以用数学推导求出通式的。但这道题目的过程要远比约瑟夫环问题复杂得多,分析通式比较困难,且由于数据量很小(少于100人),可直接按模拟类型的题目对待求解。

模拟的实现使用动态数组是非常方便的,过程也很简单。数组初始存储每一个人的编号,从第0个元素(1号)开始计数,每次杀死一个人前先不要将这个人的编号删除,而是先找出要来埋他的人,将他们的编号互换,然后将埋他的人原来所在的位置删掉即可。最后计算出的是从1号开始计数,最后能幸存的人编号p,那么从你前面第p个人开始你就是安全的(你站在第1位),即n – p。这个换算的原理是显而易见的。

这个是找你前面第p个人开始你就是安全的;

由这个人来把刚才杀掉的人埋葬,并站到被杀的人的位置上

题解:

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<vector>
 7 #include<map>
 8 #include<stack>
 9 #include<queue>
10 #define mem(x,y) memset(x,y,sizeof(x))
11 /*#define L tree[root].l
12 #define R tree[root].r
13 #define S tree[root].sum
14 #define NOW tree[root<<1].sum+tree[root<<1|1].sum
15 #define lson root<<1,l,mid
16 #define rson root<<1|1,mid+1,r*/
17 using namespace std;
18 const int INF=0x3f3f3f3f;
19 vector<int>vec;
20 int main(){
21     int n,k,flot=0;
22     while(scanf("%d%d",&n,&k),n|k){
23         vec.clear();
24         for(int i=1;i<=n;i++)
25             vec.push_back(i);
26             int pos=0,kisp=(k-1)%vec.size();
27         while(vec.size()>1){
28         pos=(kisp-1+k)%(vec.size()-1);
29         pos=(pos+(pos>=kisp))%vec.size();
30         vec[kisp]=vec[pos];
31             vec.erase(vec.begin()+pos);
32             kisp=(kisp+k-(pos<kisp))%vec.size();
33         }
34         printf("%d\n",(n - vec.front() + 1) % n + 1);
35         //printf("Case %d: %d\n",++flot,*vec.begin());
36     }
37     return 0;
38 }
时间: 2024-08-07 10:14:25

Roman Roulette(约瑟夫环模拟)的相关文章

10行Python代码解决约瑟夫环(模拟)

http://blog.csdn.net/dengyaolongacmblog/article/details/39208675 1 #!/usr/bin/env python 2 # coding: utf-8 3 4 import os 5 import sys 6 import string 7 import operator 8 import re 9 10 def josephus(n,k): 11 link=range(1,n+1) 12 ind=0 13 for loop_i in

约瑟夫环(Josehpuse)的模拟

约瑟夫环问题: 0,1,...,n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字,求出这个圆圈里剩下的最后一个数字. 这里给出以下几种解法, 1.用队列模拟 每次将前m-1个元素出队,出队元素放入队列的末尾,再循环即可,这种方法时间复杂度为O(mn)(每找出一个数字需要m步运算,要找出n人数字),空间复杂度为O(n),用于存放队列,运行结果如下. 2.环形链表模 时间复杂度为O(mn),空间复杂度为O(n) 代码如下(vs2015调试正常): 1 //Josephuse环

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

hdu 4841 圆桌问题(用vector模拟约瑟夫环)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4841 圆桌问题 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 104    Accepted Submission(s): 17 Problem Description 圆桌上围坐着2n个人.其中n个人是好人,另外n个人是坏人.如果从第一

【好记性不如烂笔头】约瑟夫环问题之形象解法(其实就是实实在在的模拟一下游戏过程)

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace 约瑟夫环游戏 8 { 9 class Program 10 { 11 /* 12 * 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围. 13 * 从编号为k的

ytu 1067: 顺序排号(约瑟夫环)

1067: 顺序排号Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 31  Solved: 16[Submit][Status][Web Board] Description 有n人围成一圈,顺序排号.从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来的第几号的那位. Input 初始人数n Output 最后一人的初始编号 Sample Input 3 Sample Output 2 HINT Source freepro

cdoj525-猴子选大王 (约瑟夫环)

http://acm.uestc.edu.cn/#/problem/show/525 猴子选大王 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status 有m个猴子围成一圈,按顺时针编号,分别为1到m.现打算从中选出一个大王.经过协商,决定选大王的规则如下:从第一个开始顺时针报数,报到n的猴子出圈,紧接着从下一个又从1顺时针循环报数,...,如此下去,最后剩

约瑟夫环——POJ3379

题目描述: 给出一个长度是n的字符串环,每次搁k个加入字符串中对应位置的字母序的下一个字母,执行m次,问最后一次插入的是什么字母. 大致思路: 正着想的话只能用模拟的方法解决,但是m有10^9这么大,而把问题倒过来想一下的话,那就变成了给出一个n+m的字符串每次搁k个字符删掉一个,最后剩下一个长度为n的字符串,问起始位置是什么字母.这样的话就变成了约瑟夫问题,约瑟夫环问题可以在不用考虑内容的情况下计算出最后剩下元素的位置.又因为字符串是一个环,所以可以假定开始的位置就是1,最后操作结束的位置就是

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