约瑟夫问题(Josephus_problem) 终极解析



Josephus_problem数学终极解法


思想来源于:http://en.wikipedia.org/wiki/Josephus_problem ,对Josephus_problem问题的阐述。

以hdu2925题为例

循环模拟方法:严重超时(代码如下)

#include

using namespace std;

struct People

{

         intnum;

         boolisLife;

};

People peopleArr[1000];

int main()

{

         freopen("input.txt","r",stdin);

   int sumPerson,count,signTime,deadNum,i;

         while(scanf("%d%d",&sumPerson,&count)== 2 && sumPerson && count)

         {

       signTime = 0;

                  deadNum= 0;

                  for(i = 1 ; i <= sumPerson; i ++)

                  {

           peopleArr[i].num = i;

                          peopleArr[i].isLife= true;

                  }

       while(deadNum != sumPerson-1)

                  {

           for(i = 1;i <= sumPerson; i ++)

                          {

                 if(peopleArr[i].isLife) 

                                    {

                                             signTime ++;

                                             if(signTime % count == 0) 

                                             {

                                                      peopleArr[i].isLife = false;

                                                      deadNum ++;

                                                      //signTime = 0;

                                             }

                                             if(deadNum = sumPerson -1)

                                                     break;

                                    }

                          }

                  }

       for(i = 1; i <= sumPerson; i ++)

                  {

                          if(peopleArr[i].isLife)

                                   //cout<

                                   printf("%d%d %d\n",sumPerson,count,peopleArr[i].num);

                  }

 

         }

         return0;

}

以上时间复杂度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,其实是没有办法在短时间内出结果的。

有的问题仅仅是要求出最后的胜利者的序号,而不是要读者模拟整个过程。

因此如果要追求效率,就要打破常规,实施一点数学策略。

约瑟夫问题(Josephus_problem) 终极解析_第1张图片

#include
using namespace std;
int f[1000010];
int main()
{
freopen("input.txt","r",stdin);
int N,D,W,i;
    while(scanf("%d%d",&N,&D) &&(N+D))
{
f[1] = 0;               
for(i = 2; i <= N; i ++)    //从零开始报数
{
f[i] = (f[i-1] + D)%i;  //数学推导当i个人数数时,赢家f[i]与f[i-1]有数学关系
}
printf("%d %d %d\n",N,D,f[N]+1);
}
return 0;
}

你可能感兴趣的:(ACM)