题意:
将 N 个数写在一个环上,顺时针数 k 个得到 x1,逆时针数 m 个得到 x2,将 x1 和 x2 输出,如果相同则只输出其中一个,输出后将其从环上删除。如此反复。
思路:
将环想象成数组,在数组上演示题意的过程,即有两个指针,一个向右移动,一个向左移动,当向右移动的指针移到结尾时再移动就会落在开头位置,当向左移动的指针移动到开头位置时,再移动就会移动到结尾处。
一开始我想的是用 vector 来存,这样可以直接删除,但是删除的逻辑比较麻烦,用数组直接做标记要来得简单许多。
我们可以将选中输出的数打上标记,这样就知道哪些数已经输出过了。
下面是对题目中样例的图解:
注意:
1. 输出时要用 “%3d”,不能用 ” %d”,我就在这个坑里摔了。。
2. 值得注意的是 x1 和 x2 是在输出后一起被删除的,而不是数出了 x1 后将 x1 删掉再去数 x2,注意这两者的不同。因为如果是后者的情况,数 x2 时如果会遇到 x1 则不会把 x1 算进去,由于 x1 已经被删掉了。
代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<stack>
#include<queue>
#include<utility>
#include<vector>
#include<cmath>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
#include<sstream>
using namespace std;
typedef long long LL;
int N, k, m;
int num[50];
int main()
{
//freopen("in.txt", "r", stdin);
while(scanf("%d%d%d", &N, &k, &m)==3 && N!=0 && k!=0 && m!=0){
memset(num, 0, sizeof(num));
for(int i=1; i<=N; i++){
num[i] = i;
}
int p = 0;
int q = N+1;
int s = N;
while(s){
for(int i=0; i<k; i++){
do{
p++;
if(p == N+1) p = 1;
}while(num[p] == 0);
}
for(int i=0; i<m; i++){
do{
q--;
if(q == 0) q = N;
}while(num[q] == 0);
}
if(p != q){
s -= 2;
printf("%3d%3d", num[p], num[q]);
num[p] = num[q] = 0;
}else {
s--;
printf("%3d", num[p]);
num[p] = 0;
}
if(s) printf(",");
else printf("\n");
}
}
return 0;
}
想看书上的源代码的话看这 (^▽^)
https://github.com/aoapc-book/aoapc-bac2nd