1,约瑟夫问题
问题:15个人排成一圈,并给他们编号1~15,现在从1号开始报数,报数字4的人退出队列,余下的人从退出者下一个位置开始继续刚才的报数,直到整个队列中只剩下一个人为止。求这个人的编号。
分析:1,如果有N个人,需要比较操作N-1次操作。
2,设定最后N个人和N-1个人的结果分别是k(n)和k(n-1),则k(n) = (k(n-1) +m)%N (解释,每次移动m次,取N的余数目的是保证结果总在【0,N),N由每次操作的人数决定),所以我们可以得到公式F(n) = (F(n-1) + m) % N
F(n-1) = (F(n-2) + m) %(N-1)
…
F(1) = 0 那么结果现在就变成了 求F(n) (从F(1)递推求)。
#include <stdio.h>
int main()
{
int n, m, i, s=0;
printf ("N M = "); scanf("%d%d", &n, &m);
for (i=2; i<=n; i++) s=(s+m)%i;
printf ("The winner is %d\n", s+1);
}
2,拉丁方阵
问题:如果用从1开始的N个连续正整数排成N*N的方阵,且每一行和每一列没有重复的数,就称其为一个N阶拉丁方阵。因为这样的方阵最早填充的是拉丁字母,因此得名拉丁方阵。例如下面给出的是一个4阶拉丁方阵:
1 2 3 4
2 3 4 1
3 4 1 2
4 1 2 3
分析:用连续【1~N】填充N*N数组,确保行列没有重复,且连续。
要保证行和列都符合条件,同时考虑会比较乱,那么先考虑确保每一行是正确的。观察上面的示例,可以看出第二行开始的编号是从上一行第二个开始,然后顺序赋值的,而去过我们的行赋值是这样的话,那么列就自然保证了。