有17個人圍成一圈,從0號的人開始報數,凡報到3的倍數的人離開圈子,然后再數下去。直到最后只剩下一個人為止。問此人原來的位置是多少號。
無意中在天涯很老的帖子看到這個問題。分析如下。
感覺這個更像是一道小學或者中學的算術題。只不過是要通過程序的方式去演示一下這個過程。
最開始我第一反應就是這道題最好倒着思考。就是將過程逆着來。
首先,我想知道一共報了多少數。因為凡是報到3的倍數的人離開圈子。而一共有17個人,最后只有一個人留下。那么有16個人離開。所以一共報了16*3=48下數。加上最后一個人,也就是49下數。這樣我定義一個長度為49的數組。初始化每個元素的值為0.我將最后一個人的身份標記為-1.
好了,接下來我們反過來看這個數組。逆着看這個過程。最開始只有一個人,他是第49個元素。接着是第48個元素。因為48%3==0.所以毫無疑問,他是離開的那個人(倒着看的時候就是要插進來的那個人。)而且我可以斷定。只要第n個元素是3的倍數,那么他就是要加進來的元素(也就是順着離開的那個元素。)
然后,我把整個過程想象成一個棧的結構。最開始棧里面只有一個人,他的序號為49,接着計算序號,如果序號是3的倍數,就往棧定新加入一個人。如果不是3的倍數,好了。我就從棧抽出元素放到棧頂。直到循環結束。
自己還是表達得不夠清楚。代碼如下:
#include<iostream>
using namespace std;
int main()
{
int a[49];
for(int i=0;i<49;i++)
{
a[i]=-4;//先把數組里面的所有元素標記為-4.最后看是不是每個元素都改變了,如果數組里面有-4,正明有漏魚
}
a[48]=-1;//把最后一個人的身份標記為-1
for(int i=47,j=48;i>=0;)
{
if((i+1)%3==0)
{
a[i]=0;//離開的人插回來,身份標記為0
i=i-1;//數組從后往前增加了一個,往前挪一位等待下一次操作。
}esle
{
a[i]=a[j];//倒敘拉人來報數。因為順序的時候報數后的人都是到最后面去等下一輪。
j=j-1;//將等待回去報數的位置往前挪一位。
i=i-1;//將等待插人報數人的位置往前挪一位。
}
}
for(int i=0;i<=48;i++)
{
cout<<a[i]<<" ";
cout<<"the length of array is:"<<sizeof(a)/4;
}
return 0;
}
最后通過打印出來的數組發現該人位於第11個位置,他的數組下表為10.
如果有錯,請留言。