Hello大家好!很高兴我们又见面啦!给生活添点passion,开始今天的编程之路!
我的博客:<但凡.
欢迎点赞,关注!
目录
1、题目
n(n个人站成一圈,逆时针编号为 1~n。有两个官员,A 从 1 开始逆时针数,B 从 n 开始顺时针数。在每一轮中,官员 A 数 k 个就停下来,官员 B 数 m 个就停下来(注意有可 能两个官员停在同一个人上)。接下来被官员选中的人(1 个或者 2 个)离开队伍。 输入 n,k,m 输出每轮里被选中的人的编号(如果有两个人,先输出被 A 选中的)。例 如,n=10,k=4,m=3,输出为 4 8, 9 5, 3 1, 2 6, 10, 7。注意:输出的每个数应当恰好占 3 列。
2、分析
我们可以让A和B开始选人,选到的人打印出来并在数组中的位置改为0,当下一次找人的时候跳过这个为0的位置。我们可以定义一个剩余的人的变量,这样当检测到剩余的人为0时结束程序。
3、题解(附详细解析)
注:输出结果和实现方式可能与原题有略微不同。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int arr[100] = { 0 };
int go(int n, int start, int d, int T)
{
while (T--)//一次走一步,走T次
{
//des = (start + d)%n;有可能下标为0,但是我们设置第一个人的下标为1
do {
start = (start + d + n - 1) % n + 1;//这样写可以让标号为0表示为标号为10
} while (arr[start] == 0);//如果该位置为0,则重复执行上一步操作
}
return start;
}
int main()
{
int n = 0;//总人数
int k = 0;
int m = 0;
int i = 0;
//A从1逆时针开始数,B从n开始顺时针数
scanf("%d %d %d", &n, &k, &m);//scanf的返回值为输入数据的个数
for (i = 1;i <= n;i++)//给予每个人标号,但注意第一个人标号为1,不是0
{
arr[i] = i;
}
int left = n;//剩余人数,注意left=n要在n不等于0时给
//go函数传入总人数起始位置,步长(这里使用步长目的是合并逆时针和顺时针到一个函数),走的步数
int startA = n;//注意,我们数的时候算着第一个人,所以我们相当于是从n作为起始位置
int startB = 1;
while (left)
{
//1为逆时针数,-1为顺时针数
startA = go(n, startA, 1, k);//返回挑选的人的标号
startB = go(n, startB, -1, m);//返回挑选的人的标号
if (startA != startB)
{
printf("%3d%3d ", startA, startB);
left -= 2;
}
else
{
printf("%3d", startA);//挑选的人相等时只打印一个
left--;
}
arr[startA] = 0;//给挑选过的人赋值为0
arr[startB] = 0;
if (left)
{
printf(",");
}
}
return 0;
}
4、拓展
其实在写这个题时我一直做不对,因为我把题中的逆时针编号看成顺时针编号了。。。
那么顺时针编号的情况下怎么实现呢?
实际上我们只需要更改两个地方就可以了。首先把A和B的起始位置更改一下,其次把传参时1和-1改一下。因为我们要1始终对应的是序号变大的方向,所以顺时针时1代表顺时针转,所以我们给A的go函数参数里为-1,B为1,实现代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int arr[100] = { 0 };
int go(int n, int start, int d, int T)
{
while (T--)//一次走一步,走T次
{
//des = (start + d)%n;有可能下标为0,但是我们设置第一个人的下标为1
do {
start = (start + d + n - 1) % n + 1;//这样写可以让标号为0表示为标号为10
} while (arr[start] == 0);//如果该位置为0,则重复执行上一步操作
}
return start;
}
int main()
{
int n = 0;//总人数
int k = 0;
int m = 0;
int i = 0;
//A从1逆时针开始数,B从n开始顺时针数
scanf("%d %d %d", &n, &k, &m);//scanf的返回值为输入数据的个数
for (i = 1;i <= n;i++)//给予每个人标号,但注意第一个人标号为1,不是0
{
arr[i] = i;
}
int left = n;//剩余人数,注意left=n要在n不等于0时给
//go函数传入总人数起始位置,步长(这里使用步长目的是合并逆时针和顺时针到一个函数),走的步数
int startA = 1;//注意,我们数的时候算着第一个人,所以我们相当于是从n作为起始位置
int startB = n;
while (left)
{
startA = go(n, startA, -1, k);//返回挑选的人的标号
startB = go(n, startB, 1, m);//返回挑选的人的标号
if (startA != startB)
{
printf("%3d%3d ", startA, startB);
left -= 2;
}
else
{
printf("%3d", startA);//挑选的人相等时只打印一个
left--;
}
arr[startA] = 0;//给挑选过的人赋值为0
arr[startB] = 0;
if (left)
{
printf(",");
}
}
return 0;
}
另外我们可以运用上面这道题的思想再来一道题:
体育课上有n个人(从1到n标号)站成一排,体育老师让他们从1开始报数,每个从报到m的人出列,最后只剩下一个人,请打印出这个人的标号。
实现代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int i = 0;
int n = 0;
int m = 0;
scanf("%d %d", &n, &m);
int arr[100] = { 0 };
for (i = 1; i <= n; i++)
{
arr[i] = i;
}
int T = n -1;
i = 0;
while(T)
{
int k = m;
while (k)
{
i = (i + 1-1) % n+1;
while (arr[i] == 0)
{
i = (i + 1 - 1) % n + 1;
}
k--;
}
arr[i] = 0;
T--;
}
for (i = 0;i < n+1;i++)
{
if(arr[i]!=0)
{
printf("%d", arr[i]);
}
}
return 0;
}
好了,今天的内容就分享到这,我们下期再见!