1. トピックの説明
円を与えられ、その円の中から最初の人をランダムに選び、その人から時計回りに数え始め、3まで数えた人は円から出て、後ろの人は1から数え始め、順番に時計回りに数え続けます。そして 3 まで数えた人がサークルから出ます...サークル内に 1 人だけ残るまで。最後に残った人の元の番号が何であるかを尋ねます。
2. アルゴリズムのアイデア
1. まず、動的メモリ割り当てを使用して、サイズが n の int 配列円を適用し、元の円をシミュレートします。配列の添字は各人の番号を表します。たとえば、circle[0] は人の番号 1 を表します。
2. ポインター p を使用して、circle[0] をポイントします。これは、最初の人から数えることを意味します。
3. ループを作成し、サークル内に 1 人だけになったらループを終了します。ループ内では、誰かがサークルから出るたびに、その位置に -1 をマークし、カウンター cnt を使用して数を数えます。cnt=3 の場合、現在のポインターが指す人の位置に -1 をマークし、カウンターを設定します。 0に設定します。
4. 各ループの後、円の中に -1 とマークされた人の数が n-1 人であるかどうかを判断し、n-1 人であればループから抜け出します。最後に、円内のマークが-1ではない位置が取り残された人の位置となり、対応する番号が出力されます。
5. 動的メモリを解放します。
3. コードの実装
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n, i, cnt = 0;
printf("请输入n的值:");
scanf("%d", &n);
// 动态内存分配申请一个大小为n的int型数组,模拟圆圈
int* circle = (int*)malloc(n * sizeof(int));
for (i = 0; i < n; i++)
{
circle[i] = i + 1; // 初始化圆圈中的每个人的编号
}
int* p = circle; // 从第一个人开始报数,指针p指向circle[0]
while (1)
{
if (*p != -1) // 如果当前位置的人没有被退出圈子,那么就开始报数
{
cnt++; // 报数+1
}
if (cnt == 3) // 如果报数为3,那么退出圈子
{
*p = -1; // 退出圈子,将此位置用-1标记
cnt = 0; // 计数器清零
}
if (p - circle == n - 1) // 如果已经到了圈子的末尾,那么就回到开头
{
p = circle;
}
else
{
p++; // 指针后移,指向下一个人
}
int out_count = 0; // 统计已经退出圈子的人数
for (i = 0; i < n; i++)
{
if (circle[i] == -1)
{
out_count++;
}
}
if (out_count == n - 1) // 如果圆圈中只剩下一个人,那么就退出循环
{
break;
}
}
for (i = 0; i < n; i++)
{
if (circle[i] != -1) // 找到圆圈中最后剩下的那个人的编号
{
printf("最后留下的是原来的第%d号的那位\n", circle[i]);
break;
}
}
free(circle); // 释放动态内存
return 0;
}