约瑟夫环

2018icpc沈阳-K.Let the Flames Begin (约瑟夫环问题)

泄露秘密 提交于 2019-11-30 02:50:48
题意: 转化为经典约瑟夫环问题: N个人围成一圈,从第一个开始报数,第K个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1。 然后现在给出 N(标号1~N)个人,每隔K个将要被杀掉,问第 M 个被杀掉的 标号是多少。(与顺时针或者逆时针无关)。 思路: 基础递推原理可以参考下 博客: https://www.cnblogs.com/jjscm/p/4463555.html 即约瑟夫环通过逆向递推,得到最初的状态。而由于要问第M个被杀掉的是谁,所以我们的初始状态不是从全部杀掉开始(长度为1),而是从(n-m+1)状态开始 而根据约瑟夫环递推式:(表示N个人,第M个出队的人是谁) f[n][m] = (f[n-1][m-1] + k)%n; 所以转换后为 f[n-m+i] = (f[n-m+i-1] + k) % (n - m + i); 由于题中数据大小为:1 ≤ n, m, k ≤ 10 18 ,以及 min{m,k} 总和不超过 2 × 10 6 ,m >= n. 所以对于 m 较大的数(会发现模数大部分情况下远大于 k k ),也就是说可以用乘法代替多次加法。 f[a][b] = ans , f[a+x][b+x] = ans + k *x; 而进行取模的条件为:ans + k*x >= a+x 即 x >= (a - ans

1012 Joseph 模拟

让人想犯罪 __ 提交于 2019-11-29 11:45:37
本题为经典约瑟夫问题。 有约瑟夫经典公式:ans[i]=(ans[i-1]+m)%i表示i个人报数,最终胜利者的编号。 本题与原本约瑟夫问题的不同点在于共有2k个人,要杀掉后k人保留前k人。而原约瑟夫问题为杀掉除自己外的所有人。所以在写代码时应注意。 1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int main(){ 5 int k=0,n=0,ans[15],count[20],m;//ans[i]表示留下k个人时且杀死所有坏人的最小编号m。 6 //count[i]表示i个人报数每报到m时杀死人的编号。 7 count[0]=0; 8 memset(ans,0,sizeof(ans)); 9 while(cin>>k){ 10 if(k==0) 11 break; 12 m=1; 13 n=2*k; 14 for(int i=1;i<=k;i++){ 15 count[i]=(count[i-1]+(m-1))%(n-i+1);//后面的除数为求编号时,考虑到m可能大于存活者人数,所有人轮过一次后新一轮才进行杀人的情况。 16 if(count[i]<k){//杀到好人了,则此m不符合要求,m递增,i重头再来。 17 m++; 18 i=0; 19 } 20 } 21 ans[k]=m; 22

约瑟夫问题

孤街浪徒 提交于 2019-11-29 03:23:57
也许更好地阅读体验 \(\mathcal{Description}\) 经典的约瑟夫问题 一开始有 \(n\) 个人围成一个圈,他们的编号从 \(0\) 到 \(n-1\) , 从 \(1\) 开始顺时针报数, 报出 \(m\) 的人被机关处决. 然后下一个人再从 \(1\) 开始报数, 直到只剩下一个人. 问最后剩下的人的编号. \(n\leq 10^{18},\ m\leq 1000\) \(\mathcal{Solution}\) 那些算法书总是把约瑟夫问题作为链表的例题来讲,初学者接触链表时还不会递推,于是一直以为只是一道链表题... 这么大的数据,当然不能链表模拟 考虑递推,还是那句话,递推的东西总是有联系的 递推时往往假设一个状态是已知的,然后试图推另一个状态,如果有递推式的话,我们就只要将最简单的状态手动求出即可 假设现在有 \(n\) 个人,第一个被处决的人的编号肯定是 \(k=(m-1)\%n\) 当编号为 \(k\) 的人被处决后,接下来我们认为是从原编号为 \(k+1\) 的人开始重新编号,然后就是一个 \(n-1\) 个人的约瑟夫问题了 当然,这 \(n-1\) 个人的答案肯定不是最终答案,因为他是重新编号后的答案,所以我们要将其恢复原编号 因为新编号为 \(0\) 的人前面有 \(m-1\) 个人,也就是编号左移了 \(m\) ,所以最终的答案应该要加上

The Dole Queue (双向约瑟夫环)

妖精的绣舞 提交于 2019-11-28 19:48:40
In a serious attempt to downsize (reduce) the dole queue, The New National Green Labour Rhinoceros Party has decided on the following strategy. Every day all dole applicants will be placed in a large circle, facing inwards. Someone is arbitrarily chosen as number 1, and the rest are numbered counter- clockwise up to N (who will be standing on 1’s left). Starting from 1 and moving counter-clockwise, one labour official counts off k applicants, while another official starts from N and moves clockwise, counting m applicants. The two who are chosen are then sent off for retraining; if both

Java实现约瑟夫环问题

烈酒焚心 提交于 2019-11-28 19:25:25
有朋友去浦发面试,因为我们是相同岗位,为了查漏补缺,便问了一下他们的机试题目。 机试考3道编程,前两道很水,最后一道他说有点麻烦,没有AC。我自己也尝试着码了一下,然后发现还是得需要耐心。 在此,我列出了三种方法,以供大家参考。 其中包括标号从0 开始的(0....(N-1)),和标号从1开始的(1....N))两个版本。 先简单说一下我的思路,前两种方法就是模拟整个过程: 1. 标号从1开始: 用动态数组存储数据,一个大循环就是数组不为空;然后利用 target = (target + k)%list.size(); 求出数组下标,对list.size()取模是为了不让target越界;那么得到的target的范围就是【0,list.size()】,然后就打印 list.get(target-1) ,所以,为了不越界,需要判断 target!=0 ,然后,再将该元素移除 list.remove(target-1); ,最后再将下标自减1(关于为什么将下标再减一,下面第2种方法中有解释)。如果 target==0 的话,那么就打印数组中最后一位 list.get(list.size()-1) ,然后再移除该元素即可。 代码如下: private static void lastPeople(int total, int k) { //初始化人数,人数排号从1开始; List

约瑟夫环

允我心安 提交于 2019-11-28 17:56:04
7-9 约瑟夫环 N个人围成一圈顺序编号,从1号开始按1、2、3......顺序报数,报p者退出圈外,其余的人再从1、2、3开始报数,报p的人再退出圈外,以此类推。 请按退出顺序输出每个退出人的原序号。 输入格式: 输入只有一行,包括一个整数N(1<=N<=3000)及一个整数p(1<=p<=5000)。 输出格式: 按退出顺序输出每个退出人的原序号,数据间以一个空格分隔,但行尾无空格。 输入样例: 在这里给出一组输入。例如: 7 3 输出样例: 3 6 2 7 5 1 4 要输出每次删的人,只能使用这个模拟 #include<iostream> #include<cstdio> using namespace std; int main() { int n,m,t=0,s=0,die=0; bool a[3010],vo=true; cin>>n>>m; for (int i=1;i<=n;i++) a[i]=0; do { t++; if (t>n) t=1; if (a[t]==0) s++; if (s==m) { s=0; a[t]=1; die++; if (vo==true) { cout<<t; vo=false; } else cout<<' '<<t; } }while (die<n); return 0; } std约瑟夫环递归算法,不能输出每个删的人

约瑟夫环

萝らか妹 提交于 2019-11-27 20:44:53
参考博客: 1、 约瑟夫环问题详解 2、 约瑟夫环 约瑟夫环问题 什么是约瑟夫环问题   约瑟夫是犹太军队的一个将军,在反抗罗马的起义中,他所率领的军队被击溃,只剩下残余的部队40余人,他们都是宁死不屈的人,所以不愿投降做叛徒。一群人表决说要死,所以用一种策略来先后杀死所有人。于是约瑟夫建议:每次由其他两人一起杀死一个人,而被杀的人的先后顺序是由抽签决定的,约瑟夫有预谋地抽到了最后一签,在杀了除了他和剩余那个人之外的最后一人,他劝服了另外一个没死的人投降了罗马   我们这个规则是这么定的:   在一间房间总共有 n 个人(下标0~n-1),只能有最后一个人活命 按照如下规则去杀人: 所有人围成一圈 顺时针报数,每次报到q的人将被杀掉 被杀掉的人将从房间内被移走 然后从被杀掉的下一个人重新报数,继续报q,再清除,直到剩余一人 推导过程: 特例1:q=2,n=2^k #n = 20 1 ==> 0#n = 40 1 2 4 ==> 0 2 ==> 0#n = 80 1 2 3 4 5 6 7 ==> 0 2 4 6 ==> 0 4 ==> 0 定义 J q= ( n= ) 为n个人,每次杀死第q个人构成的约瑟夫环最后结果,则有 jq=2(n=2^k) = 0 q=2,n=任意数   当n可以为任意数字的时候,就不会有上面这么简单的站位了,你的走位需要飘逸一点才能活到最后   举个栗子

约瑟夫环

和自甴很熟 提交于 2019-11-27 10:06:13
n个人围成一个圈,从第一个人开始编号(1,2,… ,n),从第一个人开始顺序报号1,2,3。凡报到3者退出圈子。找出最后留在圈子中的人原来的序号。要求用链表实现。 输入格式: 输入在一行中给出一个n,代表n个人围成一个圈(0<n<=100000)。 输出格式: 输出最后留在圈子中的人原来的序号,占一行。 输入样例: 10 输出样例: 4 #include<cstdio> #include<iostream> using namespace std; int a[100100]; int main() { int i,n,N,t; t=i=n=0; while(cin>>N) { for(i=0; i<N; i++) { a[i]=1; } i=0; while(t!=N-1) { if(a[i]==1) { n++; } if(n==3) { a[i]=0; n=0; t++; } i++; if(i==N) { i=0; } } for(i=0; i<N; i++) if(a[i]==1) { cout<<i+1<<endl; break; } } return 0; } 来源: https://www.cnblogs.com/dwj-2019/p/11357949.html

约瑟夫问题

杀马特。学长 韩版系。学妹 提交于 2019-11-27 08:42:59
先贴出代码 #include<malloc.h> #include<iostream> using namespace std; typedef struct node{ int num; struct node *next; } SLink; //先创建 void init(SLink *&L,int *a,int l){ L = (SLink *)malloc(sizeof(SLink)); L->num=a[0]; L->next=L; SLink *s,*pre=L; for(int i=1;i<l;i++){ s = (SLink *)malloc(sizeof(SLink)); s->next=pre->next; pre->next=s; s->num=a[i]; pre=s; // cout<<a[i]; } } //输出 void show(SLink *&L,int n){ int start=1; SLink *pre=L,*p=pre->next; while(pre->next!=pre){ //找到n的前结点n-1 while(start<n-1){ pre=p; p=p->next; start++;//到n-1、跳出循环 } //到这里了 删除p 将pre指向p的后结点 pre->next=p->next; cout<<p->num; //free

约瑟夫环

青春壹個敷衍的年華 提交于 2019-11-26 14:44:10
import java.util.ArrayList; public class test7 { /* * 约瑟夫环 */ public static void main(String[] args) { System.out.println(getluck(8)); } public static int getluck(int n) { ArrayList<Integer> a1 = new ArrayList<>(); for (int i = 1; i <= n; i++) { a1.add(i); } int count = 1; for (int i = 0; a1.size()!=1; i++) { if (i==a1.size()) { i = 0; } if (count %3==0) { a1.remove(i); i--; } if (a1.size()==1) { break; } count++; } return a1.get(0); } } 来源: https://www.cnblogs.com/yaobiluo/p/11324454.html