wy笔试题(1)

n个人围成一圈,从0开始报数,报到m-1人的退出,下一个从0开始,继续报到m-1的人退出。问最后剩下的人的序号。

输入:n和m

输出:剩下的人的序号

例如:

输入:10 2

输出:5


C++版本。

最容易想到的想法。先生成一个从1到n的数组a[n],存序号。循环遍历这个数组。用q表示剩下多少个人,用p表示计数循环(0,1,2…,n,n+1,…),如果序号为k的人退出,则设a[k]=0,用p计数时跳过等于0的人。

#include <iostream>
using namespace std;
int main(){
	int n,m;
	cin>>n>>m;
	
	int a[10000];
	for(int i=0;i<n;i++){
		a[i]=i+1;
	}
	int p=0;          //记循环
	int q=n;          //记人数
	for(int i=0;;i++){
		if(i==n) i=0;      //0,1,2,...,n-2,n-1,0,1,2...
		if(a[i]!=0) p++;   //计数
		else continue;     //跳过这个退出的人
		if(p%m==0){        //报到m-1退出,第一个报的人的p是1,所以这个是p%m
			a[i]=0;
			q--;
		}
		if(q==1) break;    //只剩一个人,退出
	}
	for(int i=0;i<n;i++){  //输出那个不为0的人
		if(a[i]!=0) cout<<a[i]<<endl;
	}
	return 0;
}

还有链表的方法,再说吧


这是个约瑟夫环问题。公式法详解。

以8个人,报数到3的人退出为例:

1 2 3 4 5 6 7 8

4 5 6 7 8 1 2

7 8 1 2 4 5

2 4 5 7 8

7 8 2 4

4 7 8

4 7

7

经典的数学问题,有递推式 f(n,m)=(f(n-1,m)+m)%n

-f(n,m):表示有n个人,报到m的人退出,最终胜利者的编号。

-f(n-1,m):表示刚刚退出了一个人,有n-1个人,报到m的人退出,最终胜利者的编号。

以上面为例,8个人中3号退出,下面一个人成为头头,则后面的人相当于往前挪了3个单位。若已知n个人时,胜利者编号为f(n,m),那n-1个人的时候,胜利者编号往前挪了,则f(n-1,m)=f(n,m)-3。递归地逻辑一般是从1开始,所以反过来从小推出大的比较容易理解代码。f(n,m)=f(n-1,m)+3,又因为他是个环,所以%当前的人数,则f(n,m)=(f(n-1,m)+3)%n。

#include <iostream>
using namespace std;
int main(){
	int n,m;
	cin>>n>>m;
	
	int p =0;
	for(int i=2;i<=n;i++){
		p = (p+m)%i;
	}
	cout<<p+1<<endl;    //从1开始给人编序号
	
	return 0;
}

tql!

猜你喜欢

转载自blog.csdn.net/qq_40189725/article/details/88656948