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......还记得约瑟夫环嘛......