菜鸟系列——约瑟夫环

菜鸟就要老老实实重新学起:

约瑟夫环:

就是长度为n的环每数m个就删去,最后留下一个。

一般问题有两种,求某种m情况下最后留下的序号

核心就是循环倒推:

for(i=2;i<=n;i++)
    res=(res+m)%i;

或者求一种m使得某一段序列最后被留下。

核心就是枚举m正向循环,同时取模求当前删去数的序号:

res=0;k=1;
for(i=0;i<n;i++)
{
    res=(res+k-1)%(2*n-i);
    if(res<n)
        i=-1,res=0,k++;
}

eg:

POJ3517 And Then There Was One

http://poj.org/problem?id=3517

题意:
简单约瑟夫环,求n长环先数m个去掉,然后每一轮数k个去掉,最后剩下的序号。
思路:
easy
code:
int main()
{
    int i,j,k,kk,t,x,y,z,res,n,m;
    while(scanf("%d%d%d",&n,&k,&m)!=EOF&&n)
    {
        for(i=2,res=0;i<n;i++)
            res=(res+k)%i;
        res=(res+m)%n;
        printf("%d\n",res+1);
    }
    return 0;
}



POJ1781 In Danger

http://poj.org/problem?id=1781

题意:

就是步长为2的约瑟夫环。

思路:

直接O(n)循环会t,但是确定了步长通过打表发现了规律,是长度为2的指数的奇数循环。

直接去掉二进制的第一位,找到循环长度得出结果。

code:
int main()
{
    int i,j,k,kk,t,x,y,z;
    while(scanf("%de%d",&n,&m)!=EOF&&n)
    {
        i=1;j=0;k=2;res=1;
        while(m--)
            n*=10;
        while(n>=i)i<<=1,j++;
        n-=(1<<(j-1));
        while(n--)res+=2;
        printf("%d\n",res);
    }
    return 0;
}


POJ1021 Joseph

http://poj.org/problem?id=1012

题意:

求长度为n的约瑟夫环用什么步长可以留下前一半数字。

思路:
数据只到14,直接枚举m即可。
code:
int main()
{
    int i,j,k,kk,t,x,y,z;
    int a[20];
    memset(a,0,sizeof(a));
    while(scanf("%d",&n)!=EOF&&n)
    {
        res=0;k=1;
        if(a[n])
        {
            printf("%d\n",a[n]);
            continue;
        }
        for(i=0;i<n;i++)
        {
            res=(res+k-1)%(2*n-i);
            if(res<n)
                i=-1,res=0,k++;
        }
        a[n]=k;
        printf("%d\n",k);
    }
    return 0;
}

POJ2244 Eeny Meeny Moo

http://poj.org/problem?id=2244

题意:

首先删去第一个,然后求在什么步长时可以最后留下第二个数。

思路:
可以看作总长n-1最后留下第一个,枚举m。
code:
int main()
{
    int i,j,k,kk,t,x,y,z;
    int a[200];
    memset(a,0,sizeof(a));
    while(scanf("%d",&n)!=EOF&&n)
    {
        res=0;k=1;
        n--;
        if(a[n])
        {
            printf("%d\n",a[n]);
            continue;
        }
        for(i=0;i<n-1;i++)
        {
            res=(res+k-1)%(n-i);
            if(res==0)
                i=-1,res=0,k++;
        }
        a[n]=k;
        printf("%d\n",k);
    }
    return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值