约瑟夫问题

约瑟夫问题

    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
",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;
}

 

 

 

 

 

 

原文地址:https://www.cnblogs.com/shenben/p/12886429.html