数论 约瑟夫环

数论 约瑟夫环

例题一:题目链接
例题二:添加链接描述

当数据比较小时,可以直接模拟暴力:

/*t=n;//模拟递推法,超时
        i=m;j=0;book[m]=1;t--;
        while(t!=1)
        {
            j++;i++;
            while(1)
            {
                if(i==n+1)
                    i=1;
                if(book[i]==1)
                    i++;
                else
                    break;
            }
            if(j==k)
            {
                j=0;
                book[i]=1;
                t--;
            }
        }
        for(i=1;i<=n;i++)
        {
            if(book[i]==0)
            {
                printf("%d\n",i);
                break;
            }
        }*/

但当数据过大时,模拟法会超时,所以通过数学的推导,有以下公式:
运用dp思想,n=2时的值可以通过n=1递归出来:
约瑟夫环数学公式:设n个人,第k个移除;
f(n)=(f(n-1)+k)%n;这是一个递推公式。
约瑟夫环:一般就是从一个人的时候(胜利者的下标是0)开始推到第n个人的时候,胜利者的下标是什么。

f(1) = 0;

f(i) = (f(i-1)+k)%i; // i表示当前环 人的人数,k表示每k个人杀。

————————————————————————————————————————
例题一代码:


#include<stdio.h>
#include<math.h>
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<string.h>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
int book[10010];
int main()
{
    int i,j,z,n,m,k,t,l;
    while(~scanf("%d%d%d",&n,&k,&m))
    {
        if(n==0&&k==0&&m==0)
            break;
        memset(book,0,sizeof(book));
        /*t=n;//模拟递推法,超时
        i=m;j=0;book[m]=1;t--;
        while(t!=1)
        {
            j++;i++;
            while(1)
            {
                if(i==n+1)
                    i=1;
                if(book[i]==1)
                    i++;
                else
                    break;
            }
            if(j==k)
            {
                j=0;
                book[i]=1;
                t--;
            }
        }
        for(i=1;i<=n;i++)
        {
            if(book[i]==0)
            {
                printf("%d\n",i);
                break;
            }
        }*/
        book[1]=0;
        for(i=2;i<=n;i++)
        {
            book[i]=(book[i-1]+k)%i;
        }
        book[n]=(book[n-1]+m)%n;//因为第一个直接删除的是第m个人,没有走流程,所以当i=n时,把k换成m
        printf("%d\n",book[n]+1);
    }
    return 0;
}
/*
约瑟夫环数学公式:设n个人,第k个移除;
f(n)=(f(n-1)+k)%n;这是一个递推公式
*/

————————————————————————————————————————
例题二代码:

/*
要求:城市2是最后一个选择的,从而找出符合该条件的m。
并且第一个城市总是第一个选择,可把问题转化为n-1个城市,第二个城市的序号为1.
根据递归公式,也就是book(n)=0即符合条件
*/
#include<stdio.h>
#include<math.h>
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<string.h>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
int book[10010];
int main()
{
    int i,j,z,n,m,k,t,l;
    while(~scanf("%d",&n))
    {
        if(n==0)
            break;
        for(m=2;;m++)
        {
            book[1]=0;
            for(i=2;i<n;i++)
            {
                book[i]=(book[i-1]+m)%i;
            }
            if(book[n-1]==0)
            {
                printf("%d\n",m);
                break;
            }
        }
    }
    return 0;
}
/*
约瑟夫环数学公式:设n个人,第k个移除;
f(n)=(f(n-1)+k)%n;这是一个递推公式
*/
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值