首页 > 其他分享 >约瑟夫环问题

约瑟夫环问题

时间:2023-05-31 23:35:42浏览次数:61  
标签:出列 int LL 约瑟夫 问题 编号 include 报数


一般约瑟夫环问题:N个人坐成一个圆环(编号为1 - N),从第1个人开始报数,数到K的人出列,后面的人重新从1开始报数。问最后剩下的人的编号。例如:N = 3,K = 2。2号先出列,然后是1号,最后剩下的是3号。


实际上对于约瑟夫环问题,最常见的有2种解法。


第一种就是直接暴力模拟链表,当然这种做法的时间复杂度很高,而且实现起来还很麻烦。第二种方法就是利用递推关系,有f[1] = 0,f[i] = (f[i-1] + K) % i;一个递推就完成,时间复杂度为O(n)。



#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;

int main()
{
    int n,k;
    while(cin>>n>>k)
    {
        int ans = 0;
        for(int i=2;i<=n;i++)
            ans = (ans + k) % i;
        cout<<ans+1<<endl;
    }
    return 0;
}




题目:http://acm.hdu.edu.cn/showproblem.php?pid=2211


题意:对于约瑟夫环问题,我们一般求的是最后一个幸存者,而本题题意是求最后一个被杀者的编号。

分析:设f(N,K)表示N个人每第K个出列的最后取出的编号。那么f(N,K)进行第一次选取后,剩下N-N/K个人,这剩下的人里最后取出的编号为f(N-N/K,K),简记为x,那么它在前一次队列里的编号为x+(x-1)/(K-1),所以f(N,K)=(x-1)/(K-1)+x,其中x=f(N-N/K,K)。



#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;

int Work(int n,int k)
{
    if(n == k) return k;
    int t = Work(n-n/k,k);
    return (t-1)/(k-1) + t;
}

int main()
{
    int T,N,K;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&N,&K);
        printf("%d\n",Work(N,K));
    }
    return 0;
}





好了,现在我们来看一下约瑟夫环问题的升级版:

N个人坐成一个圆环(编号为1 - N),从第K个人开始报数,数到M的人出列,后面的人重新从1开始报数。问最后剩下的人的编号。例如:N = 3,M = 2,K = 1。2号先出列,然后是1号,最后剩下的是3号。


对于这个问题,我们同样有递推求解方法:


LL Josephus(LL n,LL m,LL k) //参数分别为:人数,步长,起始报数位置
{
    for(LL i=1; i<=n; i++)
        k = (k + m - 1) % i + 1;
    return k;
}



这个算法的时间复杂度为O(n)。


事实上,如果我们观察上述算法中的变量k,他的初始值为第一个出圈人的编号,但在循环的过程中,我们会发现它常常处在一种等差递增的状态,我来看这个式子:k = (k + m - 1) % i +  1,可以看出,当i比较大而k+m-1比较小的时候,k就处于一种等差递增的状态,这个等差递增的过程并不是必须的,可以跳过。

我们设一中间变量 x,列出等式:k + m * x – 1 = i + x,解出x,令k = k + m * x,将i + x直接赋值给i,这样就跳过了中间共x重的循环,从而节省了等差递增的时间开销。可是其中求出来的x + i可能会超过n,这样的结果事实上已经告诉我们此时可以直接结束算法了,即:


k = k + m * (n - i) ;
i = n;

结 束。
另外对于m = 1的情况可以单独讨论:
当k == 1时,最终结果就是n;
当k != 1时,最终结果就是(k + n -  1) % n。


题目:http://acm.hdu.edu.cn/showproblem.php?pid=3089


#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;
typedef long long LL;

LL Work(LL n,LL m,LL k)
{
    if(m == 1)
        k = (k == 1 ? n:(n+k-1)%n);
    else
    {
        for(LL i=1; i<=n; i++)
        {
            if(k + m < i)
            {
                LL x = (i-k+1)/(m-1) - 1;
                if(i + x < n)
                {
                    i += x;
                    k += m*x;
                }
                else
                {
                    k += m*(n-i);
                    i = n;
                }
            }
            k = (k+m-1)%i+1;
        }
    }
    return k;
}

int main()
{
    LL n,k;
    while(cin>>n>>k)
        cout<<Work(n,k,1)<<endl;;
    return 0;
}





标签:出列,int,LL,约瑟夫,问题,编号,include,报数
From: https://blog.51cto.com/u_16146153/6391046

相关文章

  • [SprigMVC/SpringBoot] JSON序列化专题之日期序列化问题:接口报Jackson框架错误“Inva
    0序言今日工作中遇到的一个bug。各位看官且听我娓娓道来。1问题描述请求接口时,service层返回到controller层的数据结构为List<Map<Strig,Object>>,而Map中存在一个key=date,valuetype=java.time.LocalDate的Entry,且日志报如下错误:InvalidDefinitionException:Java8date......
  • sklearn gridsearch不能使用验证集导致的过拟合问题
    https://stackoverflow.com/questions/31948879/using-explicit-predefined-validation-set-for-grid-search-with-sklearn  或者用optuna####useoptunalibtofinetuneSVChyperparametersifmethod=='optuna':importoptuna......
  • 移面法+双箭头法解决所有六面体问题
    没看错,是所有!比相邻面法和公共点也许会快一些~1、移面法技巧:成直角的边可滚动滚两次:中心对称滚三次:反向滚一次141型两端可直接移231型、222型、33型可变形成141型不同型的移动图:2、双箭头法唯一需要注意:第二个箭头在哪个面,如果不好分析还可以在第二个箭头基......
  • Razor Pages本地IIS服务器部署流程及部分问题解决方法
     记录一下自己在本地IIS服务器部署的基本流程:添加IIS服务器控制面板>>程序和功能 启用或关闭windows功能>>勾选相关功能   网站部署将项目发布(publish)至本地文件夹:在包含.sln文件的目录下打开终端,输入dotnetpublish-cdebug--no-self-contained......
  • 【Azure K8S】演示修复因AKS密钥过期而导致创建服务不成功的问题(The provided client
    问题描述在AzureKubernetes服务中,创建一个InternalLoadBalancer服务,使用以下yaml内容:internallb.yamlapiVersion:v1kind:Servicemetadata:name:ilb-myappannotations:service.beta.kubernetes.io/azure-load-balancer-internal:"true"spec:type:LoadBala......
  • 无向图的最小环问题
    考试时候记错方法,然后还有其他一堆错误然后寄掉了。你TM学了个JB。所以写一篇无向图的最小环问题解法一,\(floyd\),\(O(n^3)\)for(intk=1;k<=n;++k){ for(inti=1;i<k;++i)if(k!=i) for(intj=i+1;j<k;++j)if(i!=j&&j!=k){ if(mp[i][k]......
  • 【Azure K8S】演示修复因AKS密钥过期而导致创建服务不成功的问题(The provided client
    问题描述在AzureKubernetes服务中,创建一个InternalLoadBalancer服务,使用以下yaml内容:internallb.yamlapiVersion:v1kind:Servicemetadata:name:ilb-myappannotations:service.beta.kubernetes.io/azure-load-balancer-internal:"true"spec:type:L......
  • 以样本学习方法解决设备故障检测中的标签问题
    文章的主要内容针对这些问题,提出了一种主动领域自适应智能故障检测框架LDE-ADA,该框架利用迁移学习和主动学习相结合的方法来解决标签域扩展问题,从而提高模型的检测性能。同时,提出了一种改进的主动学习查询策略,以准确选择目标域中新增加的健康类别样本来辅助模型训练,解决标签域扩......
  • Java script事件问题
    鼠标事件:/*onclick单击*/  /*ondbclick双击*/  /*onmouseover*/  /* div1.onclick=function(){    console.log('单击')  }  div1.ondbcolick=function(){    console.log('双击')  }*/ 表单事件://onsubmit事件......
  • 邮局--dp经典问题
    题目:http://poj.org/problem?id=1160题意: 一些村庄被建立在一条笔直的高速公路边上,我们用一条坐标轴来描述这条高速公路,每一个村庄的坐标都是整数,没有两个村庄坐标相同。两个村庄间的距离,定义为它们的坐标值差的绝对值。我们需要在一些村庄建立邮局——当然,并不是每一个村庄都......