思想来源于: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非常大(例如上百万,上千万)的时候,其实是没有办法在短时间内出结果的。 有的问题仅仅是要求出最后的胜利者的序号,而不是要读者模拟整个过程。 因此如果要追求效率,就要打破常规,实施一点数学策略。 #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;
}