def findTheWinner(self, n: int, k: int) -> int:
idx = 0
for length in range(2, n + 1):
idx = (idx + k) % length
return range(1, n + 1)[idx]
def lastRemaining(self, n: int, m: int) -> int:
nums = list(range(n)) # 依题意变化1~n或0~n-1
idx = cnt = 0
while len(nums) >= 2:
if cnt == m - 1:
cnt = 0
nums.pop(idx)
else:
cnt += 1
idx = (idx + 1) % len(nums)
return nums[0]
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# @Time : 2023/3/20 16:54
# @Author : Jin Echo
# @File : ring.py
"""
N个人编号1-N,围成一个环,从第一个人开始从1报数,报到M此人退出,
然后从后面一个人继续从1开始报数,当只剩一个人时,输出此人编号
"""
N, M = 5, 3
nums = list(range(1, N + 1))
i, j = 0, 0
while len(nums) > 1:
if i == M - 1:
i = 0
nums.pop(j)
print(nums)
else:
i += 1
j = (j + 1) % len(nums)
print(nums[0]) # 4
测试:
输入40 1 3
输出31
解释:共40人,编号1-40,从第一人起开始报号,报到3此人出局。则最后出局的人的编号是31
数组模拟:
/**
*1 2 3 4 5 6 7 8,第四个人,s=4,下标3
*0 1 2 3 4 5 6 7
*/
#include<iostream>
using namespace std;
void Josegh(int p[], int n, int s, int m){
for(int i=0; i<n; i++)
p[i] = i+1;
int s1 = s-1; //该轮报号起始下标
for(int i=n; i>=2; i--) { //当前还活着的人数
s1 = (s1+m-1)%i; //当前出圈人的下标
int tmp = p[s1]; //记录出圈人的编号,下面会被覆盖
int j;
for(j=s1; j<=i-2; j++)
p[j] = p[j+1];
p[j] = tmp;
//s1++; //更新下一轮报号起始下标.错误,后面往前移了,下一轮起始下边就是上一轮删除的下标
}
}
int main(){
const int MAXN = 50;
int p[MAXN];
int n, s, m;
cin>>n>>s>>m;
Josegh(p,n,s,m);
for(int i=n-1; i>=0; i--)
cout<<p[i]<<" ";
return 0;
}
Vector模拟
#include<iostream>
#include<vector>
using namespace std;
//n个人编号1-n, 从第s个人起,报到m退出
vector<int> Fun(int n, int s, int m){
vector<int> v;
vector<int>ans;
for(int i=1; i<=n; i++)
v.push_back(i);
int s1 = s-1; //第一轮的报数的起始下标
while(!v.empty()){
s1 = (s1+m-1)%v.size(); //该轮淘汰的下标,也是下轮起始报号下标。因为该轮淘汰后,后面的人往前移,此时上一轮淘汰的下标即为该轮的报数起始下标
ans.push_back(v[s1]);
v.erase(v.begin()+s1);
}
return ans;
}
int main(){
int n, s, m;
cin>>n>>s>>m;
vector<int>ans = Fun(n,s,m);
for(vector<int>::iterator it = ans.begin(); it!=ans.end(); it++)
cout<<*it<<" ";
return 0;
}
**
公式法
**
/**
*求解约瑟夫环
*n个人围成一圈,从1开始报数,报到m退出(该情形下等价于第m个人退出),下一个人重新从1开始报数,循环往复直到只剩一人,求最后一人最开始的序号
*注意:下面求解函数默认n个人的编号为0~n-1(若编号为1-n,只需把结果+1)
*递推公式:f(n,m) = [f(n-1,m)+m]%n
*只有一个人的时候, 答案为0、即n=1,f(1,m)=0;
*/
//1-41,m=3,ans=31(return p+1)
#include<iostream>
using namespace std;
int cir(int n,int m)
{
int p=0; //n=1时
//反推 ,不断的补充m个位置模上当时的数组大小
for(int i=2;i<=n;i++) //n=2~n
{
p=(p+m)%i;
}
return p; //or p+1
}
int main(){
int n,m;
cin>>n>>m;
cout<<cir(n,m);
return 0;
}