<ジョセフの質問>
1.問題の簡単な説明
ヨセフス問題は、数学的な応用問題であるヨセフスリングとも呼ばれます。
番号を報告した最初の人から始めて、n人(それぞれ1、2、3 ... nの番号)が円を描いて座っていることが知られており、番号mに報告した人の数は出て行きますサークル;次に次の人から始めて再度報告して報告するmの人はサークルから出て、最後の人が去るとゲームは終了します。残りの人の元の番号を出力します。
2.質問思考
解決したい問題:
- mに報告する人はサークル外ですが、彼がサークル外であることを示すにはどうすればよいですか?
- 問題を解決した後、サークルから抜け出す方法は?アレイの連続性を確保するために他のラベルを使用して前進するのですか、それともステータスフラグを設定するのですか?
- 配列は線形ですが、どのように円に接続しますか?
3.2つの代替実装方法
方法1:
方法:最初に、カウントの各ラウンドでサークルから外れるはずの人(mに登録した人)の位置を見つけます.1人がサークルから出た後、次のラベルを順番に前方に移動し、ループします最後の人が去るまで。
注:各人の元の番号の記録、配列内の円を離れた人の位置の検索、後ろの人の動き...
具体的なコードは次のとおりです。
#include <stdio.h>
#define N 100
int main()
{
int n,m=3,s=1;//n:总人数,m:报数值,s报数人的起始编号
scanf("%d",&n);
int a[N] = {
0};//数组初始化
int i,j;
for(i = 0; i < n; i++)//数组遍历
{
a[i] = i+1; //i是数组的位置量,a[i]是每个人的原始编号(从1开始)
}
i=s-1; //数组的起点(0)
while (n > 1)
{
i = (i+m-1) % n; //出圈的人在数组中的位置
for(j = i+1; j < n; j++)
{
a[j-1] = a[j];
}
n--; //出局1人后,总人数-1
if(i == n) //终点后,开始起点(围成一个圈)
{
i = 0;
}
}
printf("%d\n", a[i]);//输出留下的人的原始编号
return 0;
}
方法2:
方法:カウントカウントを設定し、人がサークルを離れるたびにカウントを0に設定し、毎回サークルを離れる人の後にカウントを0に設定すると、次にサークルを離れる人は1からカウントを続けます。
注:各人がサークルから出た後の合計人数は-1であるため、元のデータnが破壊されるのを防ぐために、変更にはnの代わりにxが使用されます。元の数を出力するときは、配列内で0でない人を見つけるだけです
〜ps:方法1は、カウント方法を使用して、円で囲まれた人の位置を見つけることもできます〜
具体的なコードは次のとおりです。
#include <stdio.h>
#define N 50
int main()
{
int a[N], m, n, x, i, count = 0;
printf("Please input n m:\n");
scanf("%d %d", &n, &m); //输入总人数n和出局要报的数m
x = n; //把n赋给x,防止使用时n被修改
for (i = 1; i <= n; i++) //数组遍历,此时在数组中的位置就是人原来的编号
{
a[i] = i;
}
while(x>1)
{
for (i = 1; i <= n; i++)
{
if (a[i] != 0) //判断是否出圈,已经出局的就不用报数了
{
count++; //报数
}
if (count == m)
{
a[i] = 0; //出圈的人置为0,而后不参与报数
count = 0;
x--; //出圈一个,总人数减1
}
}
} //循环结束后,出圈的人都已经被置为0,留下唯一一个人
for (i = 1; i <= n; i++)
if(a[i]!=0)
printf("%d ",i); //输出留下的人的原始编号
return 0;
}
ヒント:Josephの問題では、再帰と決済リストを使用することもできます。