HDOJ 1443 约瑟夫环的最新应用分析详解

 更新时间:2013年05月24日 11:23:40   作者:  
本篇文章是对HDOJ 1443 约瑟夫环的最新应用进行了详细的分析介绍,需要的朋友参考下
k个男生和k个女生站成一列,前面k个是男生,后面k个是女生,从第一个男生开始报数,报到队列最后一个同学,循环到队首继续报,并且如果一个同学报到的数是m,这个同学就出列,然后后面的同学继续从1开始报数,现在求一个数m,使k个女生全部出列,而男生没有出列。

输入:男生女生的个数k(男生女生人数相等都为k,输出:m值
例: 输入:2,输出:7
输入:4,输出:30

本题是约瑟夫环变形 先引入Joseph递推公式,设有n个人(0,...,n-1),数m,则第i轮出局的人为f(i)=(f(i-1)+m-1)%(n-i+1),f(0)=0; f(i) 表示当前子序列中要退出的那个人(当前序列编号为0~(n-i));
拿个例子说:K=4,M=30;
复制代码 代码如下:

f(0)=0;
      f(1)=(f(0)+30-1)%8=5; 序列(0,1,2,3,4,5,6,7)中的5
      f(2)=(f(1)+30-1)%7=6; 序列(0,1,2,3,4,6,7)中的7
      f(3)=(f(2)+30-1)%6=5; 序列(0,1,2,3,4,6)中的6
      f(4)=(f(3)+30-1)%5=4; 序列(0,1,2,3,4)中的4
      ........

依据题意,前K个退出的人必定是后K个人,所以只要前k轮中只要有一次f(i)<k则此m不符合题意。
注意:
本题有几点需要注意,否则很容易超时;
第一点、运用公式j=(j+m-1)%(n-i),推导出下一个出现的元素在第几号位置,如果j<k的话,不符合题意。
第二点、就是m,当只剩下k+1个数的时候,则上一个消失的数一定是在目前仅剩的bad左边或者是右边,所以m%(k+1)==0或者1
有了这两个条件,可以加快程序的速度。。。
完整的实现代码如下:
复制代码 代码如下:

#include "stdio.h"
#include "stdlib.h"
int x[15];
/*
运用公式j=(j+m-1)%(len-i);推导出下一个出现的元素在第几号位置,如果j<k的话,不符合题意。
若有7个人,报到3的人依次出列
第一次 j=(j+m-1)%(len-i)=(0+3-1)%(7-0)=2   下标为2的3出列   新序列为  1 2 4 5 6 7
第二次 j=(j+m-1)%(len-i)=(2+3-1)%(7-1)=4   下标为4的6出列   新序列为  1 2 4 5 7
第三次 j=(j+m-1)%(len-i)=(4+3-1)%(7-2)=1   下标为1的2出列   新序列为  1 4 5 7
第四次 j=(j+m-1)%(len-i)=(1+3-1)%(7-3)=3   下标为3的7出列   新序列为  1 4 5
第五次 j=(j+m-1)%(len-i)=(3+3-1)%(7-4)=2   下标为2的5出列   新序列为  1 4
第六次 j=(j+m-1)%(len-i)=(2+3-1)%(7-5)=0   下标为0的1出列   新序列为  4
第七次 j=(j+m-1)%(len-i)=(0+3-1)%(7-6)=0   下标为0的4出列   新序列为空,至此,所有人已经全部出列,出列的顺序为:3 6 2 7 5 1 4
*/
int test(int k,int m)
{
 int i,j=0,len=k*2;
 for(i=0;i<k;i++)
 {
  j=(j+m-1)%(len-i);    //约瑟夫环公式
  if(j<k)
   return 0;     //遇到前k轮中有小于k的直接返回0
 }
 return 1;
}
/*
接下来说说m的取值范围:我们考察一下只剩下k+1个人时候情况,即坏人还有一个未被处决,
那么在这一轮中结束位置必定在最后一个坏人,那么开始位置在哪呢?这就需要找K+2个人的结束位置,
然而K+2个人的结束位置必定是第K+2个人或者第K+1个人,这样就出现两种顺序情况:GGGG.....GGGXB 或  GGGG......GGGBX (X表示有K+2个人的那一轮退出的人)所以有K+1个人的那一轮的开始位置有两种可能即最后一个位置或K+1的那个位置,限定m有两种可能:
GGGG......GGGBX 若K+2个人的结束位置在最后一个(第K+2个),则m%(k+1)==0
GGGG......GGGXB 若K+2个人的结束位置在倒数第二个(第K+1个),则m%(k+1)==1
*/
void Joseph(void)
{
 int m,k;
 for(k=1;k<15;k++)
 {
  m=k+1;
  while(1)
  {
   if(test(k,m))     // m%(k+1)==0的情况
   {
    x[k]=m;
    break;
   }
   if(test(k,m+1))     // m%(k+1)==1的情况
   {
    x[k]=m+1;
    break;
   }
   m+=k+1;
  }
 }
}
int main(void)
{
    int k;
 Joseph();
 while(scanf("%d",&k),k)
  printf("%d\n",x[k]);
 system("pause");
}

相关文章

  • C++类的继承和派生及指针安全引用

    C++类的继承和派生及指针安全引用

    这篇文章主要介绍了C++类的继承和派生及指针安全引用,继承指从现有类获得其特性,派生指从已有类产生新的类,指针和引用并存,二者似乎有很多相同点,但是又不完全相同,下面关于两者的相关资料,需要的小伙伴可以参考一下
    2022-03-03
  • 详解C++ 重载运算符和重载函数

    详解C++ 重载运算符和重载函数

    这篇文章主要介绍了C++ 重载运算符和重载函数的的相关资料,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • C语言执行程序时遇到的常见问题及解决

    C语言执行程序时遇到的常见问题及解决

    这篇文章主要介绍了C语言执行程序时遇到的常见问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • c语言printf实现同一位置打印输出的实例

    c语言printf实现同一位置打印输出的实例

    下面小编就为大家带来一篇c语言printf实现同一位置打印输出的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • c语言实现MD5算法的项目实践

    c语言实现MD5算法的项目实践

    MD5用于确保信息传输完整一致,是计算机广泛使用的杂凑算法之一,本文主要介绍了c语言实现MD5算法,具有一定的参考价值,感兴趣的可以了解一下
    2023-08-08
  • 深入理解c++模板中的class与typename

    深入理解c++模板中的class与typename

    在c++Template中很多地方都用到了typename与class这两个关键字,而且好像可以替换,是不是这两个关键字完全一样呢?下面这篇文章主要给大家介绍了关于c++模板中class与typename的相关资料,需要的朋友可以参考下。
    2017-07-07
  • C++ getcwd函数获取项目运行路径方法详解

    C++ getcwd函数获取项目运行路径方法详解

    在Linux下做QT项目时,需要获取项目的运行路径,于是用getcwd函数进行获取,然后在Windows下进行测试,发现获取到的是程序的项目路径,即代码文件路径,然后再Linux QT中测试,获取到的又是运行路径,这就很纳闷了。经过再三测试,终于发现了原因
    2022-10-10
  • C语言实现数独游戏的求解

    C语言实现数独游戏的求解

    这篇文章主要为大家详细介绍了C语言实现数独游戏的求解,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • 剑指offer之判断链表是否包含环

    剑指offer之判断链表是否包含环

    今天小编就为大家分享一篇关于剑指offer之判断链表是否包含环,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-02-02
  • C++ OpenCV实现图像双三次插值算法详解

    C++ OpenCV实现图像双三次插值算法详解

    图像双三次插值的原理,就是目标图像的每一个像素都是由原图上相对应点周围的4x4=16个像素经过加权之后再相加得到的。本文主要介绍了通过C++ OpenCV实现图像双三次插值算法,需要的可以参考一下
    2021-12-12

最新评论