N个人占城一圈,逆时针编号为1~n.有两个官员,A从1开始逆时针数,B从n顺时针开始。在每一轮中,官员A数k个数就停下来,官员B数m个就停下来(注意有可能连个官员停在同一个人上)。接下来被官员选中的人离开队伍。
输入n,k,m输出每轮里被选中的人的编号(如果有两个人)先输出被A选中的)。注意:输出的每个数应当恰好占3列。
【分析】
仍然采用自顶向下的方法编写程序,用一个大小为0的数组表示人站成的圈。为了避免人走之后移动数组元素,用0表示离开队伍的人,数数时跳过即可。主程序如下:
#include
const int MAXN = 25;
int n,k,m;
int a[MAXN];
int go(int p, int d, int k);//数过k个人,开始位置p必须是数1时候的前一个位置。
int main() {
while (scanf("%d%d%d", &n, &k, &m) == 3 && n) {
for (int i = 0; i < n; i++) {//逆时针编号
a[i] = i + 1;
}
int left = n;
int pA = n-1, pB = 0;
int pANext,pBNext;
while (left) {
pA = go(pA, 1, k);//1表示逆时针,因为它是逆时针标号,从n的前一位开始
pB = go(pB, -1, m);//-1表示顺时针。从1的下一位开始
printf("%3d", pA + 1); left--;
if (pA != pB) { printf("%3d", pB + 1); left--;}
a[pA] = a[pB] = 0;//选到的人标记为0,下次遇到后跳过
if (left) printf(",");
}
printf("\n");
}
return 0;
}
int go(int p, int d, int L) {
while (L--) {
do { p = (p+n+d)%n;} while(a[p] == 0);
}
return p;
}
#include
using namespace std ;
const int maxn = 10000 ;
int queue1[maxn] , queue2[maxn] ;
void init( int n )
{
memset( queue1 , 0 , sizeof( queue1 ) ) ;
memset( queue2 , 0 , sizeof( queue2 ) ) ; //正逆两个方向分别用两个数组记录编号
for( int i = 0 ; i < n ; i++ )
queue1[i] = i + 1 ;
int count = 0 ;
for( int i = n - 1 ; i >= 0 ; i-- )
queue2[count++] = queue1[i] ;
return ;
}
int find( int a , int arr[] , int begin , int end )
{
int pos = -1 ;
for( int i = begin ; i < end ; i++ )
if( arr[i] == a ) { pos = i ; break ; }
return pos ;
}
void change( int a[] , int pos , int end )
{
for( int i = pos ; i < end -1 ; i++ )
a[i] = a[i+1] ;
return ;
}
int main()
{
int n = 0 , m = 0 , k = 0 ;
while( cin >> n >> m >> k )
{
if( ! n && ! m && ! k ) break ;
init( n ) ;
int front1 = 0 , front2 = 0 ;
int rear1 = n , rear2 = n ;
int count = 0 ;
int flag = 0 ;
while( rear1 > front1 ) //当队列不为空
{
if( flag ) cout << "," ;
flag = 1 ;
//顺时针找下一个人,并让不是下一个人的人重新入队
for( int i = 0 ; i < m - 1 ; i++ )
queue1[rear1++] = queue1[front1++] ;
int first = queue1[front1] ;
//逆时针找下一个人,并让不是下一个人的人重新入队
for( int i = 0 ; i < k - 1 ; i++ )
queue2[rear2++] = queue2[front2++] ;
int second = queue2[front2] ;
//输出找到的人
if( first == second ){ printf( "%3d" , first ) ; count++ ;}
else { printf( "%3d%3d" , first , second ) ; count += 2 ; }
//找应该删除的人,并且删除
int pos = find( first , queue1 , front1 , rear1 ) ;
if( pos != -1 && pos > front1 )//pos < front1说明这个位置不在队列里
{ change( queue1 , pos , rear1 ) ;rear1-- ; }//每删除一个就要把队尾指针给往回倒一
pos = find( second , queue1 , front1 , rear1 ) ;
if( pos != -1 && pos > front1 )
{ change( queue1 , pos , rear1 ) ;rear1-- ; }
pos = find( first , queue2 , front2 , rear2 ) ;
if( pos != -1 && pos > front2 )
{ change( queue2 , pos , rear2 ) ; rear2-- ; }
pos = find( second , queue2 , front2 , rear2 ) ;
if( pos != -1 && pos > front2 )
{ change( queue2 , pos , rear2 ) ; rear2-- ; }
front1++ ; front2++ ;//队首元素出队
}
if( count < n ) printf( ",%3d" , queue1[rear1] ) ;
cout << endl ;
}
return 0 ;
}