1.问题提出
学院某系要在本系154个同学中选派一半同学即77人参加夏令营,由于报名踊跃,争执不下,系学生会主席王小明提议实施按学号围圈、报数淘汰的办法实施筛选:同学们学号为1,2,。。,154,按学号顺序逆时针方向围成一圈。小明的学号为1号,从1号开始逆时针方向1,2,。。。,报数,凡报数m者出圈淘汰,如此继续报数淘汰。直到最后剩下77人确定参加夏令营。
为了确保公正,报数数m由通常摇双骰子确定,两个色子点之和(显然为区间[2,12]中的正整数]确定为报数数m。他具体举例说,例如双色子点数之和为8,即按1,2,3.。。8逆时针方向沿圈报数,凡报数8者出圈淘汰。
系计算机兴趣小组3位编程高手在计算这一选派方法后有人欢喜有人愁。小林认为他幸运占据了一个无忧位:无论m在2,3,。。。,12中取什么数,他都能确保不被淘汰出局。不陈学号比小林大,他也是无忧位。小张则直叫不好,他说他是一个绝望位:无论m在2,3,。。。,12中取什么数,他都将被淘汰出局。请问:
①小林、小陈与小张的学号分别是什么编号?
②如果把人数拓广到任意三位偶数时,按这一筛选一半同学的方法,当学生数为多少时小明1号是无忧位?当学生数为多少时小明的1号是绝望位?
2.设计思路
设置数组a[n],第一数组赋初值1。同时设置报数数m(2~12)循环,对每一个m实施报数,每报数一人,变量w增1.当加a(i)后变量w的值为m时,置a(i)=0,标志编号为i者出圈。设置y统计出圈人数。同时,w=0并重新逆时针方向后报数累加。
当编号i增至n+1时则i=1。
当出圈人数y达到n/2人时,即未出圈者只剩n/2人,终止报数。
然后应用数组s(i)统计出局的编号i的次数,s(i)的值都初始化为11,在报数的过程中,若i号则s(i)--。对于m=2,3,...,12这11个数,若s(i)=11(即面临11个报数数,每次都未被淘汰),位转即为无忧位;若s(i)=0(即面临11个报数,每次都被淘汰),位置i即为绝望位。
3.代码实现
// 圆圈中的无忧位与绝望位 #include "stdafx.h" #define MAXN 1000 int main(void) { // y表示为出圈人数,n为人数,m为最大报数 // w为每报数一人则加1 int y, w, i, n, m; static int s[MAXN], a[MAXN]; printf("请输入人数:"); scanf("%d", &n); for (i = 1; i <= n; i++) s[i] = 11; for (m = 2; m <= 12; m++) { for (i = 1; i <= n; i++) a[i] = 1; y = 0; w = 0; i = 1; while (y < n / 2) { if (a[i]) { w += a[i]; // 按逆时针顺序报数 if (w == m) // 报数m者出圈赋0 { a[i] = 0; w = 0; y++; s[i]--; } } i++; if (i > n) i = 1; // 又从头开始报数 } } for (i = 1; i <= n; i++) { if (11 == s[i]) printf("/n无忧位:%d/n", i); if (!s[i]) printf("绝望位:%d/n", i); } return 0; }
4.对指定区间内偶数人时指定编号为无忧位与绝望位探索
在以上无忧位与绝望位设计的基础上,增加一个人数n循环。对于n人中的第x号位,如果m取2,3,。。。,12这11个数被淘汰,即s(x)=0,人数n作绝望位打印输出。
5.代码
// 指定敬意内偶数丛里指定编号为无忧位与绝望位探索 #include "stdafx.h" #define MAXN 3000 int main(void) { int c, d, y, w, i, n, m, x; static int s[MAXN], a[MAXN]; printf("请输入人数区间: "); scanf("%d%d", &c, &d); printf("请输入指定号: "); scanf("%d", &x); if (c < x) // 确保起点c不小于编号x c = x; if (c % 2) // 确保c为偶数 c++; for (n = c; n <= d; n += 2) { for (i = 1; i <= n; i++) s[i] = 11; for (m = 2; m <= 12; m++) { for (i = 1; i <= n; i++) a[i] = 1; y = 0; w = 0; i = 1; while (y < n / 2) { // 出圈人数不足n/2时继续报数 if (a[i]) { w += a[i]; // 按逆时针顺序报数 if (w == m) { a[i] = w = 0; y++; s[i]--; } } i++; if (i > n) i = 1; } } if (11 == s[x]) printf("/n当人数为%d时,%d号为无忧位。", n, x); if (!s[x]) printf("/n当人数为%d时,%d号为绝望位。", n, x); } return 0; }
转《趣味C程序设计集锦》