问题描述: n个人(id:1~n)围成一圈 从第一人开始计数 每数到3 那个人离去 ,然后从下一个人开始 重新从1开始计数,请问最后一个人离开是的谁? 答案用id表示
解决思路:
用指针数组存储ID数组每个元素的地址,每次循环减少指针数组元素的个数,但是ID数组元素内容变化,地址不变(关键步骤),最后剩下的指针数组元素指向剩下人物的ID,该方法比循环链表速度快 复杂度相当
为解释我的想法 我举个实例:
假设有6个人玩约瑟夫环游戏:1,2,3,4,5,6 L为初始围圈人数(L=6)
第一次循环有6个人: 1,2,3,4,5,6
id为4,6的人离开圈子,剩下的id为: 1,2,4,5
我在这里做个映射,预测1,2,4,5在下一次循环的id
L=6
第一个人 ID:1->7(第一个人在第二圈的id)7=1+L(6为当前圈子人数,因为数到1,还没有离开圈子,所以下一次到第一个人的时候,必然为1+L)
L=6
第二个人 ID: 2-> 8 (第二个人在第二圈的id)8=2+L(6为当前圈子人数,因为数到2,还没有离开圈子,所以下一次到第一个人的时候,必然为2+L)
第三个人离开了
L=5
第四个个人 ID: 4-> 9 (第四个人在第二圈的id)9=4+L(5为当前圈子人数,因为数到3时,有一个人离开圈子,X下一个人要填补它的位置,所以下一次到第一个人的时候,必然为4+L)
L=5
第五个人 id: 5-> 10(第五个人在第二圈的id)10=5+L(5为当前圈子人数,因为数到3时,有一个人离开圈子,所以下一次到第一个人的时候,必然为5+L)
第二圈循环时有四个人: 7,8,9,10
id为9的人离开圈子,剩下的为7,8,10
再预测7,8,10在第三圈的ID
以此类推 最后剩下一个人
指针数组法
#include <stdio.h>
#include <stdlib.h>
void choose(int *c[],int j)
{
int h,i,k;
int **q;
q=c;
h=j;
while(h>1){ //h为当前圈内人数
k=0;
for(i=0;i<j;i++) //每次循环的圈内人数
{
if(**q%3==0) {h--;}
else {
c[k]=c[i];
*c[k]=*c[k]+h; //更新留在圈内的人在下一次循环的ID
k++;
}
q++;
}
j=h;
q=c;
}
}
int main(int argc, char *argv[])
{
int k,i;
printf("请输入围圈人数\n");
scanf("%d",&k);
int a[k][1],*b[k];
for(i=0;i<k;i++)
{
a[i][0]=i+1;
b[i]=a[i];
}
int *p;
p=a[0];
choose(b,k);
printf("%d\n",b[0]-p+1);
system("PAUSE");
return 0;
}