UVA133
题目的意思是把一对人围成一圈, 随机选一个作为标号1, 并且逆时针(count-clockwise)编号,也就是说1位于左边,N位于右边。然后有两个官员,一个从编号1开始计数,计数为k,到达后停下。一个从N开始计数,计数为m,到达后停下。在所停下的这个人面前离开队列。接着继续计数直到没有人为止。因为两个人是同时开始的,所以可能会遇到同时达到同一个位置。这时候一个人出队列就行。
分析
思维很简单, 编写walk(start, stepSize, direct)函数,实现从start位置开始,该位置为无效位置(既下一个有效位置的最近的无效位置, direc为方向)。因为逆时针的时候,数字是增加的,顺时针的时候数字是减小的,所以direct = 1表示逆时针。
实现walk的方式更为简单, 每次走一步, 判断边界条件(=0和>N), 并且判断该位置是否有效,有效则stepSize-1, 直到stepSize==0,停下的位置就是出队列的位置。
总结
任何复杂的问题, 都可以通过抽象的定义来屏蔽复杂的细节。就如通过walk方法, 先定义好该方法,然后根据定义实现该方法即可。
//
// Created by sixleaves on 2016/11/23.
//
#include <cstdio>
#include <cstring>
// direct == 1 表示逆时针, 起点从N开始
// direct == -1 表示顺时针, 起点从1开始
// 表示从start位置开始走, 走stepSize步, start位置是最靠近下一个有效位置的无效位置.(start, start + stepSize]
int n, k, m;
int applicant[26];
int walk(int start, int stepSize, int direct);
int main() {
while (scanf("%d%d%d", &n, &k, &m) == 3 && n && k && m) {
for (int i = 0; i<=n; i++) applicant[i] = i;
int left = n;
int p1 = n;
int p2 = 1;
while (left) {
p1 = walk(p1, k, 1);
p2 = walk(p2, m, -1);
applicant[p1] = 0;
left--;
if (p1 != p2) {
applicant[p2] = 0;
printf("%3d%3d", p1, p2);
left--;
}else {
printf("%3d", p1);
}
if (left) printf(",");
}
printf("\n");
}
return 0;
}
int walk(int start, int stepSize, int direct) {
int index = -1;
while (true) {
start = start + direct;
if (start > n) start = 1;
if (start == 0) start = n;
if (applicant[start] == 0) continue;
if (applicant[start])
stepSize--;
if (stepSize <= 0) break;
}
index = applicant[start];
return index;
}