f(sixleaves) = sixleaves

重剑无锋 大巧不工

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  95 随笔 :: 0 文章 :: 7 评论 :: 0 Trackbacks

题目描述

为了缩短领救济品的队伍,NNGLRP决定了以下策略:每天所有来申请救济品的人会被放在一个大圆圈,面朝里面。选定一个人为编号 1 号,其他的就从那个人开始逆时针开始编号直到 N。一个官员一开始逆时针数,数 k 个申请者,然后另一个官员第 N 个始顺时针方向数 m 个申请者,这两个人就被送去再教育。如果两个官员数的是同一个人,那个人则被送去从政,然后2个官员再在剩下的人里面继续选直到没人剩下来,注意两个被选 中的人是同时走掉的,所以就有可能两个官员选中一个人。

[编辑]Input

输入含有多组测试资料,每组测试资料一列含有三个数 N,k 和 m(k, m > 0,0<N<20)。 当输入为 0 0 0 代表输入结束。

[编辑]Output

对每组测试资料输出一列。输出被选中的申请者的编号顺序(一对一对的)。每个数的宽度为 3 。每一对前面的那个编号为逆时针数的官员选出的,后面的那个编号为顺时针数的官员选出的(但是如果这2个官员选出同一个人,那就只会有一个编号)。每一对 之间以逗号分开。格式请参考Sample Output。

[编辑]Sample Input

10 4 3 
13 17 42
7 8 47
0 0 0

[编辑]Sample Output

 4 8, 9 5, 3 1, 2 6, 10, 7 
4 11, 10 1, 8 6, 13 7, 3, 5 12, 9 2
1 3, 5 7, 2 4, 6
这道题目有点绕,也讲得不严密。这里主要说下几个容易错的地方。
首先是你每次在写程序之前,都要十分清除规则,题目中的人是围着一圈,而且第一个的左边是第N个人,也就是它是逆时针标号的。这个十分关键。
其次是go函数的实现,go函数是数过L个人,返回最后一个的位置。我并不赞同,某些版本数组是从1开始计数,因为这样对于表达式的表达十分不方便。你可以
自己尝试用1来做,会很不方便。就是因为go函数是这样一个函数,所以当我们在下一次迭代的时候的开始位置,一定是为那个人出去的位置,也就是a[i]=0的位置。
所以我们第一次迭代的位置,原本A是应该在位置0,B在位置n-1。这时候只能是A在n-1和B在0.(你可以用数学归纳法理解)。
 1 #include <stdio.h>
 2 
 3 #define MAXN 25
 4 int n,k,m;
 5 int a[MAXN];
 6 int go(int p, int d, int k);//数过k个人,开始位置p必须是数1时候的前一个位置。 
 7 int main() {
 8     while (scanf("%d%d%d", &n, &k, &m) == 3 && n) {
 9         for (int i = 0; i < n; i++) {
10             a[i] = i + 1;
11         }
12         int left = n;
13         int pA = n-1, pB = 0;
14         int pANext,pBNext;
15         while (left) {
16             pA = go(pA, 1, k);//1表示逆时针,因为它是逆时针标号
17             pB = go(pB, -1, m);//-1表示顺时针
18             printf("%3d", pA + 1); left--;
19             if (pA != pB) { printf("%3d", pB + 1); left--;}
20             a[pA] = a[pB] = 0;
21             if (left) printf(",");
22         }
23         printf("\n");
24     }    
25     return 0;
26 }
27 int go(int p, int d, int L) {
28     while (L--) {
29         do { p = (p+n+d)%n;} while(a[p] == 0);
30     }
31     return p;
32 }
解析:至于下一个位置为什么是p = (p+n+d)%n.其实很简单。因为我们是一步步走的,所以只有两种边界情况。假设当前位置是p(0=<p<n),
第一种边界:p + 1 > n - 1,即 p + 1此时应该是到达0位置,但此时p + 1 = n,如果我们取余数,则 (p+1)%T = 0,T = n(T表示这个圆圈的周期大小)。
刚好能符合,又因为T = n,所以(P+T+1)%T还是不变的。
第二种边界: p - 1 < 0, 即 p - 1此时的值是-1,对于这种情况可以反过来看,它是向后退后1个单位,可以看成向前走T - 1个单位即p -1 等效于 p + T - 1
,我们要等到此时的位置,再去余,(P+T-1)%T。
对于情况一、二。可以归纳为(P+T+d)%T,当为顺时针是d取1,否则-1.
posted on 2014-09-23 20:46 swp 阅读(1801) 评论(0)  编辑 收藏 引用 所属分类: algorithm

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理