据说著名犹太历史学家 Josephus 有过以下故事:在罗马人占领乔塔帕特后,39 个犹太人与 Josephus 及他的朋友躲到一个洞中,39 个犹太人决定宁愿死也不要被敌人抓到,于是决定了一种自杀方式,41 个人排成一个圆圈,由第 1 个人开始报数,报数到 3 的人就自杀,然后再由下一个人重新报 1,报数到 3 的人再自杀,这样依次下去,直到剩下最后一个人时,那个人可以自由选择自己的命运。这就是著名的约瑟夫问题。现在请用单向环形链表得出最终存活的人的编号。
一行两个整数 n 和 m, n 表示环形链表的长度, m 表示每次报数到 m 就自杀。
输出最后存活下来的人编号(编号从1开始到n)
5 2
3
#include <iostream> #include <queue> using namespace std; queue<int> q; int main(){ int n, m; cin >> n >> m; for(int i = 1; i <= n; i++){ q.push(i); } while(q.size() != 1){ //m-1个人重新入队 for(int i = 1; i < m; i++){ q.push(q.front()); q.pop(); } q.pop(); } cout << q.front() << "\n"; return 0; }或者运用向量
#include <iostream> #include <queue> #include <vector> using namespace std; queue<int> q; vector<int> v; int main(){ int n, m, i; cin >> n >> m; for(i = 1; i <= n; i++){ v.push_back(i); } i = 0; while(!v.empty()){ i = (i + m) % v.size(); if(i == 0){ q.push(v[v.size() - 1]); v.erase(v.end() - 1); i = v.size(); }else{ q.push(v[i - 1]); v.erase(v.begin() + i - 1); i -= 1; } } cout << q.back() << "\n"; //清空队列和向量 v.clear(); v.shrink_to_fit(); while(!q.empty()){ q.pop(); } return 0; }
import java.util.*; public class Main { public static void main(String[] args){ Scanner input = new Scanner(System.in); while(input.hasNextInt()){ int n = input.nextInt(); int m = input.nextInt(); int ans = getResult(n,m); System.out.println( ans ); } input.close(); } /** * 这是一个仿真程序 */ public static int getResult(int n, int m) { // write code here boolean[] r = new boolean[n]; //record序列,r[i]用于记录第i个人是否已被淘汰,初始为false int pass = 0; //已淘汰数 int i = 0; int sum = 0; //目前数到第sum个 while(pass < n){ if(i == n) i = 0; if(r[i] == false){ //第i人未淘汰 sum++; if(sum == m){ //淘汰当前报数者 pass++; r[i] = true; sum = 0; //1人出局后,重新报数 continue; } i++; }else //第i人淘汰 i++; } return i+1; //自然序比程序下标大1. } }
#include <iostream> #include <vector> using namespace std; int m, n; struct node { int val; node* next; }; node* fun(node* head, int m) { if (head == nullptr || head->next == head || m < 1) return head; node* last = head; while (last->next != head) last = last->next; int cnt = 0; while (head != last) { if (++cnt == m) { last->next = head->next; cnt = 0; } else { last = last->next; } head = last->next; } return head; } int main() { cin >> n >> m; node* head = nullptr; node* p = nullptr; for (int i = 1; i <= n; i++) { if (head == nullptr) { head = new node; head->val = i; head->next = nullptr; p = head; continue; } p->next = new node; p = p->next; p->val = i; p->next = nullptr; } p->next = head; node* node1 = fun(head, m); cout << node1->val << endl; system("pause"); return 0; }
/*简单模拟*/ #include <stdio.h> #include <stdlib.h> typedef struct nd { int val; struct nd *next; } node; node *create_node(int val) { node *n = (node *) malloc(sizeof(node)); n->val = val; n->next = NULL; return n; } node *josephus_kill(node *head, int m) { int tmp = 1; node *pre, *cur = head; while (cur->next != head) cur = cur->next; pre = cur; cur = head; while (cur->next != cur) { if (tmp == m) { tmp = 1; pre->next = cur->next; free(cur); cur = pre->next; continue; } pre = cur; cur = cur->next; tmp++; } return cur; } int main(void) { int n, m; scanf("%d%d", &n, &m); node dh = {0, NULL}, *cur = &dh; for (int i = 0; i < n; i++) { cur->next = create_node(i + 1); cur = cur->next; } cur->next = dh.next; cur = josephus_kill(dh.next, m); printf("%d\n", cur->val); return 0; }
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; class ListNode { public int val; public ListNode next; public ListNode(int val) { this.val = val; } } public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] params = br.readLine().split(" "); int n = Integer.parseInt(params[0]), m = Integer.parseInt(params[1]); ListNode head = new ListNode(1); ListNode cur = head; for(int i = 2; i <= n; i++){ cur.next = new ListNode(i); cur = cur.next; } int live = 1; // 长度为1时,剩下节点的编号 // 倒推得到长度为n时它的编号 for(int i = 2; i <= n; i++) live = (live + m - 1) % i + 1; cur = head; for(int i = 1; i < live; i++) cur = cur.next; System.out.println(cur.val); } }直接用链表模拟的话每报数m次就删除一个节点,一共要删除n-1个节点,因此时间复杂度为O(mn);而用公式倒推的话需要调用n-1次时间复杂度为O(1)的公式,整体时间复杂度为O(n)。
#include <bits/stdc++.h> using namespace std; int main(){ int n, m; cin >> n >> m; int alive = 0; for(int i = 2; i <= n; i++){ alive = (alive + m)%i; } cout << alive+1 <<endl; return 0; }
import java.util.*; class node{ int val; node next; public node(){}; public node(int val) { this.val = val; } } public class Code61_yuesefuProblem { public static void main(String[] args) { node ans = new node(); node index = ans; Scanner in = new Scanner(System.in); node mynode = new node(); int n = in.nextInt(); int m=in.nextInt(); for (int i = 1; i <= n; i++) { node temp = new node(i); index.next = temp; index = index.next; } index.next = ans; int ch=n; int count=1; node p=ans; node q=ans.next; while(ch!=1) { if (count == m &&q.val!=0) { //System.out.println("所删除的节点"+q.val); q = q.next; p.next = q; count = 1; ch--; } else if (count != m &&q.val!=0) { p = p.next; q = q.next; count++; } else{ p=p.next; q=q.next; } } node test=ans.next; while(true) { if(test.val!=0){ System.out.println(test.val); break; } test=test.next; } } }
大概思路 1.就是循环赋值然后附完值后让指针指向头形成单循环链表 2.然后删除用的基本操作遇到对应的删除节点时前指针先走一步然后后指针指向他删除该指针并且计数器count置为1,如果不是的话就俩指针各走一步然后count++ 3.对了我加了一个q.val!=0是因为我创建的链表是带头节点的方便操作但是头节点不参与循环所以到他的时候基数器不参与任何变化
#include<iostream> using namespace std; int main() { //数学解法 int n,m; cin>>n>>m; int r=0; for(int i=2;i<=n;i++){ r=(r+m)%i; //上一轮编号 } cout<<r+1; return 0; }
let [n,m]=readline().split(' ').map(item=>parseInt(item)) const listNode=function(val){ this.val=val this.next=null } let head=new listNode(-1) let p=head for(let i=0;i<n;i++){ const node=new listNode(i+1) p.next=node p=node } p.next=head.next head.next=null let q=p p=q.next // 计算每轮生存节点 // const getLive=function(n,m){ // if(n==1) return 1 // else return (getLive(n-1,m)+m-1)%n+1 // } // const compute=function(head,m){ // if(head==null||head.next==head||m<1) return head // let count=getLive(n,m) // while(count>1){ // head=head.next // count-- // } // console.log(head.val) // } const compute=function(){ if(head==null||head.next==head||m<1) return head let count=1 for(let i=2;i<=n;i++){ count=(count+m-1)%i+1 } // while(count>1){ // head=head.next // count-- // } console.log(count) } compute()
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int m = sc.nextInt(); //初始化队列 Queue<Integer> queue = new LinkedList<>(); //向队列中添加元素 for (int i=1; i<=n; i++){ queue.offer(i); } //判断队列的元素是否为1 while (queue.size() != 1){ //向队列尾部添加队列前m-1个元素,同时删除队列前m-1个元素 for (int i=1; i<m; i++){ queue.offer(queue.poll()); } //删除队列第m个元素 queue.poll(); } //如果队列只有1个元素,输出元素,不删除队列元素 System.out.println(queue.peek()); } }