约瑟夫问题
约瑟夫问题一般有两种解决方法,一种数组,一种链表,本次采用数组方式说明解决。
规则:
n个人围成一个圈,每个人分别标注为1、2、...、n,要求从1号从1开始报数,报到k的人出圈,接着下一个人又从1开始报数,如此循环,直到只剩最后一个人时,该人即为胜利者。例如当n=10,k=4时,依次出列的人分别为4、8、2、7、3、10,9、1、6、5,则5号位置的人为胜利者。给定n个人,请你编程计算出最后胜利者标号数。
步骤:
(1) 为了程序可扩展性,数组大小定义大一些,然后根据用户输入来确定参加游戏的人数和要杀掉的人的位置数。
(2) 当循环超过用户定义的游戏人数时定义一个简单算法重新开始。
(3) 如果这个人没死就报数。
(4) 如果报的数是要杀死的位置数但没有死n-1个人则标志死亡人数,然后游戏继续。
(5) 如果报的数是要杀死的位置数但是已经死了n-1个,即只剩余该人一人时就打印该人的位置数。
流程图:
略。
代码:
int main()
{
int n, k;
int i;
int a[1001];
int dead = 0; //表示已经死了多少人
int num = 0; //num模拟没有被杀的人的人数
printf("n个人围成一个圈,每个人分别标注为1、2、...、n,要求从1号从1开始报数,报到k的人出圈,接着下一个人又从1开始报数,如此循环,直到只剩最后一个人时,该人即为胜利者。例如当n=10,k=4时,依次出列的人分别为4、8、2、7、3、10,9、1、6、5,则5号位置的人为胜利者。给定n个人,请你编程计算出最后胜利者标号数。(要求用单循环链表完成。)第一行为人数n;第二行为报数k:\n");
scanf("%d%d", &n, &k);
for (i = 1; i <= n; i++)
a[i] = i;
//开始时每个人都可以报数,为了能得到最后一个人的编号,我们让初始值为i下标
for (i = 1;; i++)
{
if (i > n)
i = i%n; //如果大于总人数,我们就从头开始
if (a[i] > 0) //如果当前这个人没有死,就报数
num++;
if (k == num && dead != n - 1) //如果当前这个人报的数等于k并且没有已经死亡n-1个人
{
num = 0;
a[i] = 0; dead++;
}
//如果这个人报数等于k,并且已经死了n-1个人,说明当前这个人就是最后的一个活着的了。。
else if (k == num && dead == n - 1)
{
printf("%d", a[i]);
break;
}
}
return 0;
}
结果: