问题描述: 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; }