约瑟夫问题
约瑟夫问题
N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。
模拟整个过程或只输出最后一个人的编号
参考百度约瑟夫问题
循环模拟全过程$O(nm)$
#include<cstdio> #include<cstring> using namespace std; const int N=1e6+10; int n,t; bool vis[N]; void deal(int m){ int tot=n; int p=0; for(int i=1;tot>1;i++){ if(i>n) i=1; if(vis[i]) continue; if(++p==m) p=0,vis[i]=1,tot--; } for(int i=1;i<=n;i++) if(!vis[i]){printf("%d\n",i);return ;} } int main(){ freopen("resist.in","r",stdin); freopen("resist.out","w",stdout); scanf("%d%d",&n,&t); deal(t); return 0; }
线段树模拟全过程$O(nlog_2n)$
#include<bits/stdc++.h> using namespace std; #define N 30005 #define lc k<<1 #define rc k<<1|1 int n,k,a[N<<2]; void build(int k,int l,int r){ if(l==r){ a[k]=1;return ; } int mid=l+r>>1; build(lc,l,mid); build(rc,mid+1,r); a[k]=a[lc]+a[rc]; } int query(int k,int l,int r,int pos){ if(l==r){ a[k]=0;return l; } int mid=l+r>>1,ans; if(a[lc]>=pos) ans=query(lc,l,mid,pos); else ans=query(rc,mid+1,r,pos-a[lc]); a[k]=a[lc]+a[rc]; return ans; } int main(){ scanf("%d%d",&n,&k); build(1,1,n); for(int i=1,tmp=k;i<=n;i++){ printf("%d ",query(1,1,n,tmp)); if(i!=n) tmp=(tmp+k-1)%(n-i); if(!tmp) tmp=n-i; } return 0; }
递推只输出最后一个人的编号$O(n)$
#include<cstdio> using namespace std; int n,m,s; int main(){ freopen("resist.in","r",stdin); freopen("resist.out","w",stdout); scanf("%d%d",&n,&m); for(int i=2;i<=n;i++) s=(s+m)%i; printf("%d",s+1); return 0; }