约瑟夫环是一个数学应用题:已知n个人(编号1、2、..n)围坐在一张圆桌周围。从编号为1的人开始报数,数到m的那个人出列;他的下一个又从1开始报数,数到m的那个人又出列;依次规律重复下去,直到圆桌周围的人全部出列。请编写一个程序,给定n、m计算出列人员先后顺序。
#include<list> #include<iostream> #include<vector> using namespace std; vector<int> Yuesefu(int n, int m) { list<int> myList; vector<int> res; for (int i = 1; i <= n; i++) myList.push_back(i); int index = 0; while (myList.size() > 1) { list<int>::iterator it = myList.begin(); index = (index + m - 1) % myList.size(); advance(it, index); res.push_back(*it); myList.erase(it); } return res; } int main() { int n, m; cin >> n; cin >> m; vector<int> res = Yuesefu(n, m); for (int i = 0; i < res.size(); i++) cout << res[i] << endl; }
# *_* coding: utf-8 *_*
class Node():
def __init__(self, data):
self.data = data
self.next = None
def create(n):
head = Node(1)
p = head
for i in range(2, n+1):
q = Node(i)
p.next = q
p = q
p.next = head
return head
def get_sequence(n, m):
linklist = create(n)
print("check created linklist")
print(linklist.data)
print(linklist.next.data)
print(linklist.next.next.data)
print(linklist.next.next.next.data)
print(linklist.next.next.next.next.data)
print(linklist.next.next.next.next.next.data)
print(linklist.next.next.next.next.next.next.data)
print('*' * 20)
p = linklist
while p.next != p:
for i in range(1, m):
q = p
p = p.next
# print the mth node
print(p.data)
q.next = p.next
p = p.next
# print the last one in the list
print(p.data)
def main():
n, m = 7, 5
get_sequence(n, m)
if __name__ == '__main__':
main()
约瑟夫问题的数列转换解法,原理参照:[https://www.nowcoder.com/questionTerminal/11b018d042444d4d9ca4914c7b84a968](https://www.nowcoder.com/questionTerminal/11b018d042444d4d9ca4914c7b84a968)
======================================================================
链接:https://www.nowcoder.com/questionTerminal/11b018d042444d4d9ca4914c7b84a968
来源:牛客网
把n个人的编号改为0~n-1,然后对删除的过程进行分析。
第一个删除的数字是(m-1)%n,几位k,则剩余的编号为(0,1,...,k-1,k+1,...,n-1),下次开始删除时,顺序为(k+1,...,n-1,0,1,...k-1)。
用f(n,m)表示从(0~n-1)开始删除后的最终结果。
用q(n-1,m)表示从(k+1,...,n-1,0,1,...k-1)开始删除后的最终结果。
则f(n,m)=q(n-1,m)。
下面把(k+1,...,n-1,0,1,...k-1)转换为(0~n-2)的形式,即
k+1对应0
k+2对于1
...
k-1对应n-2
转化函数设为p(x)=(x-k-1)%n, p(x)的你函数为p^(x)=(x+k+1)%n。
则f(n,m)=q(n-1,m)=p^(f(n-1,m))=(f(n-1,m)+k+1)%n,又因为k=(m-1)%n。
f(n,m)=(f(n-1,m)+m)%n;
最终的递推关系式为
f(1,m) = 0; (n=1)
public ArrayList transfer(int n,int m){ ArrayList res = new ArrayList(); if(n<=0) return res; for(int i=1;i<=n;i++) {//将序列1-n表示为0-(n-1),方便通过求余的方法求出每次被选中的元素 int index = (m-1)%i;//每次被抽取的数,逆向添加数 res.add(index); for(int j=0;j<res.size();j++) {//转化n-1次 if(i<n)//未到最后一次,仍然需要转化 res.set(j, (res.get(j)+m)%(i+1)); if(i==n) {//转化完成 res.set(j, (res.get(j)+1)); } } } Collections.reverse(res); return res; }
ArrayList<Integer> list = new ArrayList<>(n); List<Integer> returnList=new ArrayList<>(n); if (n == 0 || m == 0) { return list; } for (int i = 1; i <= n; i++) { list.add(i); } int index=0; for (int i = 0; i < n; i++) { index=(index+m-1)%list.size(); returnList.add(list.get(index)); list.remove(index); } return (ArrayList<Integer>) returnList;
//方法很多#include <iostream>#include<vector>#include<algorithm>usingnamespacestd;voidgetpop(vector<int>&pp,vector<int>num,intm){intcursize=num.size(),cnt=0,index=-1;vector<int>state(cursize);fill(state.begin(),state.end(),0);while(cursize>0){++cnt;index=(index+1)%num.size();while(state[index]!=0)index=(index+1)%num.size();if(cnt==m){pp.push_back(num[index]);cnt=0;--cursize;state[index]=1;}}}intmain(){intm,n;cin>>n>>m;vector<int>num(n);iota(num.begin(),num.end(),1);vector<int>p;getpop(p,num,m);for(inti=0;i<p.size();++i)cout<<p[i]<<" ";cout<<endl;return0;}
public class calOutOrder { public static void main(String[] args) { cal(10, 3); } /** * 输出报数m的人的编号 * * @param n 人数 * @param m 报数出列 */ public static void cal(int n, int m) { int[] outList = new int[n + 1]; int outNum = 0; for (int i = 1, count = 0; outNum < n; i = i < n ? i + 1 : 1) { if (outList[i] == 0) { count++; if (count == m) { count = 0; outList[i] = 1; outNum++; System.out.println(i); } } } } }
//java版 import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class Ysf { public static void main (String[] args) { System.out.println("please input n:");//总数 Scanner scanner=new Scanner(System.in); int n=scanner.nextInt(); System.out.println("please input k:");//开始编号,从1到n int k=scanner.nextInt(); System.out.println("please input m:");//增量 int m=scanner.nextInt(); System.out.println("*****************************************"); ysf(n,k,m); scanner.close(); } static void ysf(int n,int k,int m) { List<Integer> list=new ArrayList<Integer>(); for (int i=0;i<n;i++) { list.add(i+1); } int index=k-1; while(list.size()>0) { index=(index+1+m)%list.size()-1; if(index==-1) { System.out.println(list.get(list.size()-1)); list.remove(list.size()-1); index=0; } else { System.out.println(list.get(index)); list.remove(index); } } } }
#include<stdio.h> int main() { int num[100]; int m,n,i,k=0,s=0; printf("请输入总人数n和输出序号m:\n"); scanf("%d%d",&m,&n); for(i=1;i<=n;i++) num[i]=i; i=1; while(k<=n) //k统计出队的人数 { if(num[i]!=0) s++; //表示报数报到第几个人 if(s==m) { printf("%4d",i); num[i]=0; k++; s=0; } ++i; if(i>n) i=1; } }
// 约瑟夫环的问题 循环链表 // m 表示跳几个位置 n 表示几个人 import java.util.Scanner; public class test1 { public static class Node{ // 建立内部节点类 int val ; // 节点的值 Node next; // 下一个节点的地址 public Node(int val){ this.val = val; } } public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); // 总人数 int m = sc.nextInt(); // 跳几个 // 建立循环单链表 Node head = new Node(1); // 头节点 Node cur = head; for (int i = 2; i<=n;i++){ cur.next= new Node(i); cur = cur.next; } cur.next = head ; cur = cur.next; // 指向头节点 Node p ; while (cur.next!=cur){ // 当不是一个节点时 for (int i = 1 ;i<m-1;i++){ // 循环为m-2 cur = cur.next; } p = cur.next; // 指向循环后的第一个节点 System.out.print(p.val+"--"); // 输出该值 cur.next = p.next; // cur = p.next; // 删除节点操作 } System.out.print(cur.val); // 输出该值 } }
import java.util.*; public class Main{ public static void main(String[] args) { josephRing(10,5); } private static void josephRing(int n, int m) { ArrayList<Integer> list = new ArrayList<>(); for (int i = 1; i <= n; i ++) { list.add(i); } int index = m - 1; while (list.size() != 0) { index %= list.size(); System.out.print(list.remove(index) + "\t"); index += m - 1; } System.out.println(); } }
#include "stdafx.h" #include <iostream> #include <vector> using namespace std; struct List { List(int a = 0,List * b=NULL):x(a),next(b) {} int x; List * next; }; void recurise(vector<int> & ans, List * head, int & m) { List * tmp = head; if (tmp->next == tmp) { ans.push_back(tmp->x); return; } for (int i = 2; i<m; ++i) tmp = tmp->next; ans.push_back(tmp->next->x); tmp->next = tmp->next->next; recurise(ans, tmp->next, m); } List * create_List(int n) { List * head = new List(1, NULL),* tmp=head; for (int i = 2; i <= n; ++i) { tmp->next = new List(i, NULL); tmp = tmp->next; } tmp->next = head; return head; } void delete_List(List * head) { for (List * tmp=head,* save;;) { save = tmp->next; if (save == head) break; delete tmp; tmp = save; } } int main(void) { int m, n; vector<int> ans; List * head; while (cin >> n >> m) { head=create_List(n); recurise(ans,head, m); delete_List(head); for (int i = 0; i < ans.size(); ++i) cout << ans[i] << " "; cout << endl; ans = {}; } }循环链表,可以解决,但是如果使用循环数组,时间复杂度太大,不应该采用,此时,整个算法时间复杂度为O(mn),空间复杂度为O(n);