The Dole Queue——Uva_133

In a serious attempt to downsize (reduce) the dole queue, The New National Green Labour RhinocerosParty has decided on the following strategy. Every day all dole applicants will be placed in a largecircle, facing inwards. Someone is arbitrarily chosen as number 1, and the rest are numbered counter-clockwise up to N (who will be standing on 1’s left). Starting from 1 and moving counter-clockwise,one labour o cial counts o k applicants, while another o cial starts from N and moves clockwise,counting m applicants. The two who are chosen are then sent o for retraining; if both o cials pickthe same person she (he) is sent o to become a politician. Each o cial then starts counting againat the next available person and the process continues until no-one is left. Note that the two victims(sorry, trainees) leave the ring simultaneously, so it is possible for one o cial to count a person alreadyselected by the other o cial.

Input

Write a program that will successively read in (in that order) the three numbers (N , k and m; k, m > 0,0 < N < 20) and determine the order in which the applicants are sent o for retraining. Each set ofthree numbers will be on a separate line and the end of data will be signalled by three zeroes (0 0 0).

Output

For each triplet, output a single line of numbers specifying the order in which people are chosen. Eachnumber should be in a eld of 3 characters. For pairs of numbers list the person chosen by the counter-clockwise o cial rst. Separate successive pairs (or singletons) by commas (but there should not be atrailing comma).

Note: The symbol in the Sample Output below represents a space.

Sample Input

10 4 3

0 0 0

Sample Output

␣␣4␣␣8,␣␣9␣␣5,␣␣3␣␣1,␣␣2␣␣6,␣10,␣␣7

本题反思:

    这道题原来一直想用数组进行模拟,但不是向书中一样模拟(就是p = (p + d + n - 1) % n + 1这种想法),而是真的使用for循环一个接着一个进行枚举。思来想去感觉,啊不对还是因为自己太懒了。。。懒得用这种笨方法,于是直接使用的书上的方法A的题......


贴上书上的代码吧......

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n, k, m, a[25];

int go(int p, int d, int t)
{
    while(t--)
    {
        do
        {
            p = (p + d + n - 1) % n + 1;
        }while(a[p] == 0);//走到下一个非零的数字
    }
    return p;
}

int main(){
    while(scanf("%d%d%d", &n, &k, &m) == 3 && (n != 0 && k != 0 && m != 0))
    {
        for(int i = 1; i <= n; i++)
            a[i] = i;
        int left = n;
        int p1 = n, p2 = 1;
        while(left)
        {
            p1 = go(p1, 1, k);
            p2 = go(p2, -1, m);
            printf("%3d", p1);
            left--;
            if(p2 != p1)
            {
                printf("%3d", p2);
                left--;
            }
            a[p1] = a[p2] = 0;
            if(left)
                printf(",");
        }
        printf("\n");
    }
	return 0;
}

其实说到为啥不想再去想其他的方法了呢,因为我觉得书上的方法就是非常值得学习的,虽然基础但也是我不太会使用的。于是多敲一遍印象就加深了一些。


这种方法的可取之处在于:

  • 使用标记0和1来表示选中的人和没有选中的人,逻辑清晰。
  • 相比较笨拙的for前后模拟,这种方法抽象出了函数,其中用+1和-1来表示顺/逆,值得学习。
  • ......(纯粹是智商因素...我就是容易在这个地方卡壳......)记住:p = (p + d + n - 1) % n + 1......还记得约瑟夫环嘛......



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值