CH3-UVA133

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 
#include 

// 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;
}

你可能感兴趣的:(CH3-UVA133)