春晚的魔术实际上是一个约瑟夫问题,最终的结果是魔术开始时确定的几个变量确定好的,扑克牌只是道具和障眼法。网上一查这个问题发现颇有历史渊源,17世纪的法国数学家加斯帕在《数目的游戏问题》中讲了这样一个故事:15个教徒和15 个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行直到仅余15个人为止。问怎样排法,才能使每次投入大海的都是非教徒。
编程实现这个过程:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int last_one(int n, int m)
{
	int res = 0;
	if (n == 1) {
		return 1;
	}
	for (int i = 2; i < n + 1; ++i) {
		res = (res + m) % i;
	}
	return res + 1;
}
int main(void)
{
	int n, m, i, kill = 0, t = 0, s = 0;
	scanf("%d %d", &n, &m);
	printf("%s line %d, total object %d, kill every %d object.\n",
	       __func__, __LINE__, n, m);
	// the first object are reserved, the first index start from
	// 1, end to n.
	bool *array = malloc(sizeof(bool) * (n + 1));
	if (array == NULL) {
		printf("%s line %d, alloc object buffer failure.\n",
		       __func__, __LINE__);
		return -1;
	}
	for (i = 0; i < (n + 1); i ++) {
		array[i] = false;
	}
	do {
		++t;
		if (t > n)
			t = 1;
		if (!array[t])
			s++;
		if (s == m) {
			s = 0;
			printf("%d ", t);
			// kill this object.
			array[t] = true;
			kill++;
		}
	} while (kill != n); // all has been killed.
	printf("kill %d object, last one is %d.\n", kill, last_one(n, m));
	free(array);
	return 0;
}
可见杀戮顺序是9 18 27 6 16 26 7 19 30 12 24 8 22 5 23 11 29 17 10 2 28 25 1 4 15 13 14 3 20 21,所以只要保证9 18 27 6 16 26 7 19 30 12 24 8 22 5 23位置上的人都是非教徒,则15名教徒能够全部存活下来。

所以,只要把非教徒安排在5,6,7,8,9,12,16,18,19,22,23,24,26,27,30位置上,能够达到仅杀死非教徒的目的。
参考文章
约瑟夫环问题(链表 + 公式)-CSDN博客








![[ai笔记3] ai春晚观后感-谈谈ai与艺术](https://img-blog.csdnimg.cn/img_convert/3f79d9ca4a9b800a1dfa88c5a5190ac6.png)










