直接给自己写的约瑟夫问题的函数吧!
适用条件:当编号是从1开始,数到m 出局。最后只剩下一个的话。(也就是本题的约瑟夫情况)
int Joseph(int n, int m) {//这里n是总数,m是数到n的人退出,num为最后剩余的人生
int *Array = new int[n];//动态申请n个单元的数组,每个单元代表一个人
int k = 0;
/*当人的编号是从1开始的时候*/
for (int i = 0; i<n; i++) {
Array[i] = i + 1;//
}
for (int i = n; i > 1; i--) {//最后保留几个人这里的i就大于几
k = (k + m - 1) % i;//需要退出的人所在数组的下标
for (int j = k; j < i; j++)
Array[j] = Array[j + 1];//i=n的时候应该算是越界了
}
int result = Array[0];
delete[] Array;
return result;
}
思路:典型的约瑟夫环问题。
· 这里先简单的写一下本题的解题思路。
· 首先用的是数组进行数据的存储的,输入n个人,就动态的申请n个单元的数组:int *Array = new int[n];
· 然后初始化每一个数组(数组表示的值代表编号)
·这里写一下总结的小公式: int K=0 ;
K=(K+m-1)%i
a[0] a[1] a[2] a[3] a[4] a[5] a[6]………….
1 2 3 4 5 6 7 ………….
1 2 4 5 6 7 ………….
1 2 4 5 7 ………….
1 4 5 7 ………….
1 4 5 ………….
1 4 ………….
1 ………….
K=(0+3-1)%7=2
K=(2+3-1)%6=4
K=(4+3-1)%5=1
K=(1+3-1)%4=3
K=(3+3-1)%3=2
K=(2+3-1)%2=0
上面的K表示的是即将退出的人所在单元的下标这里%的总数是变化的,因为每次出局一个人之后需要将数组重新进行一次调整:用后面单元的内容覆盖前面的内容,同时单元总数相应的减少
也就是:for (int i = n; i>1; i--) {
k = (k + 3 - 1) % i;//需要退出的人所在数组的下标
for (int j = k; j<i; j++)
Array[j] = Array[j + 1];
}
这样第一个for循环的次数为n-1次,最后只剩下0号单元人没退出,输出它的值即可!cout << Array[0] << endl;
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<stack>
#include<queue>
using namespace std;
//int Array[10000];
int main() {
int n;
cin >> n;
int *Array = new int[n];//动态申请n个单元的数组,每个单元代表一个人
for (int i = 0; i<n; i++) {
Array[i] = i+1;//
}
int k = 0;
for (int i = n; i>1; i--) {
k = (k + 3 - 1) % i;//需要退出的人所在数组的下标
for (int j = k; j<i; j++)
Array[j] = Array[j + 1];
}
cout << Array[0] << endl;
delete[] Array;
return 0;
}
好了,用了两个for循环,本题除了用数组去做,也可以考虑用链表去做做!
下面罗列几种约瑟夫问题可能的情况(用数组写的话):
1)就是按照本题的,n个人 ,从1开始编号,数到m的退出,最后就剩下一个
int Joseph(int n, int m) {//这里n是总数,m是数到n的人退出,num为最后剩余的人生
int *Array = new int[n];//动态申请n个单元的数组,每个单元代表一个人
int k = 0;
/*当人的编号是从1开始的时候*/
for (int i = 0; i<n; i++) {
Array[i] = i + 1;//
}
for (int i = n; i > 1; i--) {//最后保留几个人这里的i就大于几
k = (k + m - 1) % i;//需要退出的人所在数组的下标
for (int j = k; j < i; j++)
Array[j] = Array[j + 1];//i=n的时候应该算是越界了
}
int result = Array[0];
delete[] Array;
return result;
}
2)如果是从0开始的话:
· 首先数组的下标开始的时候是和编号对应的,但是还是要初始化:
只是公式应该为 int k=0 ;k=(k+m)% i;
int Joseph(int n, int m) {//这里n是总数,m是数到n的人退出,num为最后剩余的人生
int *Array = new int[n];//动态申请n个单元的数组,每个单元代表一个人
int k = 0;
/*当人的编号是从1开始的时候*/
for (int i = 0; i<n; i++) {
Array[i] = i ;//
}
for (int i = n; i > 1; i--) {//最后保留几个人这里的i就大于几
k = (k + m) % i;//需要退出的人所在数组的下标
for (int j = k; j < i; j++)
Array[j] = Array[j + 1];//i=n的时候应该算是越界了
}
int result = Array[0];
delete[] Array;
return result;
}
3)最后保留几个数据就在上面两种代码中的
```
for (int i = n; i > 1; i--) {//最后保留几个人这里的i就大于几
i大于1的1改成需要保留的数目。