In a serious attempt to downsize (reduce) thedole queue, The New National Green Labor Rhinoceros Party has decided on thefollowing strategy. Every day all dole applicants will be placed in a largecircle, facing inwards. Someone is arbitrarily chosen as number 1, and the restare numbered counter-clockwise up to N (who will be standing on 1's left).Starting from 1 and moving counter-clockwise, one labour official counts off kapplicants, while another official starts from N and moves clockwise, countingm applicants. The two who are chosen are then sent off for retraining; if bothofficials pick the same person she (he) is sent off to become a politician.Each official then starts counting again at the next available person and theprocess continues until no-one is left. Note that the two victims (sorry,trainees) leave the ring simultaneously, so it is possible for one official tocount a person already selected by the other official.
Write a program that will successively readin (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 off forretraining. Each set of three numbers will be on a separate line and the end ofdata will be signaled by three zeroes (0 0 0).
For each triplet, output a single line ofnumbers specifying the order in which people are chosen. Each number should bein a field of 3 characters. For pairs of numbers list the person chosen by thecounter-clockwise official first. Separate successive pairs (or singletons) bycommas (but there should not be a trailing comma).
10 4 3
0 0 0
4 8, 9 5, 3 1, 2 6, 10, 7
where representsa space.
方法一(麻烦但是好想):
#include<iostream>
#include<iomanip>
using namespace std;
int num[30];
int main()
{
int n,k,m;
while(cin>>n>>k>>m&&n)
{
for(int i=0;i<n;i++)
{
num[i]=i+1;
}
int left=n;
int a=0,b=n-1+100*n;//防止产生负数
while(left)
{
int flag1=0,flag2=0;
for(; ;a++)
{
if(num[a%n])
{
flag1++;
}
if(flag1==k)
{
cout<<setw(3)<<num[a%n];//逆时针优先
left--;
break;
}
}
for(;;b--)
{
if(num[b%n])
{
flag2++;
}
if(flag2==m)
{
if(num[b%n]!=num[a%n])
{
cout<<setw(3)<<num[b%n];
left--;
break;
}
break;
}
}
if(left)
{
cout<<",";
}
else
{
cout<<endl;
}
num[b%n]=0;
num[a%n]=0;
}
}
}
方法二:(精简但是不好想)
#include<iomanip>//输出宽度控制
using namespace std;
int n,k,m;
int num[30];//存连续正整数的数组
int run(int pos,int add,int sum);//当前位置,每次移动的增量,需要移动的总次数
int main()
{
while(cin>>n>>k>>m&&n!=0)
{
for(int i=1;i<=n;i++)
{
num[i]=i;
}
int acwp=0,cwp=n+1;// acwp:逆时针查数的前一个未知的索引;
//cwp:顺时针查数的后一个位置的索引
int left=n;//总的数字中未被查到的数字的个数
while(left)
{
acwp=run(acwp,1,k);//逆时针查数
cwp=run(cwp,-1,m);//顺时针查数
num[acwp]=0;//题意为优先逆时针(当顺逆均查到同一位置时)
left--;//未被查到的数字减少一个
cout<<setw(3)<<acwp;//优先输出
if(acwp!=cwp)//只有当顺逆查到的数字不相同时才对顺时针进行输出
{
left--;
num[cwp]=0;
cout<<setw(3)<<cwp;
}
if(left)//当还有数字没查时,输出逗号
{
cout<<",";
}
}
cout<<endl;//每测试完一组数据,输出换行
}
}
int run(int pos,int add,int sum)
{
while(sum--)//写成--sum就循环少了一次
{
do
{
pos=(pos+add+n-1)%n+1;//统一了移动是向前还是向后的操作;从N变成1好理解;从1变成N这样理解:向后退一个单位相当于向前走了N-1个单位
}
while(num[pos]==0);//只要下一个位置被查到过(==0),就继续向下查找,直到查到的数字不为0
}
return pos;//返回索引
}