约瑟夫环问题---2020牛客国庆集训派对day2 AKU NEGARAKU
2020-10-3
·
hexer

题面

链接:https://ac.nowcoder.com/acm/contest/7818/A 来源:牛客网

时间限制:C/C++ 3秒,其他语言6秒 空间限制:C/C++ 262144K,其他语言524288K 64bit IO Format: %lld 题目描述 1st Academy is an international leadership training academy based in Kuala Lumpur. Every year, the company trains thousands of people to be supplied to companies around the world. To be fair amongst all the trainees, the company will do the selection process using numbering system. The trainees will choose a number from 1 to N, and one number is not limited to only one trainee. The N represents the total number of companies that request trainees from the academy. A number, M, would be picked at random, and the selection starts with a trainee whose number is 1, and then in every M’th people after that, wrapping around to 1 after N, and ignoring trainees already selected. For example, if N = 15 and M = 6, trainees would be selected in the order: 6, 12, 3, 10, 2, 11, 5, 15, 13, 9, 14, 4, 1, 8, 7. All the selected trainees except the last one (which is number 7) will be supplied to companies outside of Malaysia. However, Leong preferred to stay and work in Malaysia. To him, there is no better place other than Malaysia. He does not mind being located anywhere as long it is Malaysia. As a friend of him, you could help him to choose a number that will save him from being located outside. Input 输入描述: Input will consist of a series of lines, each line containing the number of companies (N) with 1 \leq N \leq 15001≤N≤1500, and a skipping value (M) with 1 \leq M \leq 501≤M≤50. The values will be terminated by a line consisting of double zeros (0 0) as shown in sample input output. 输出描述: Output will consist of a series of lines, one for each line of the input. Each line will consist of the number M according to the above scheme. 示例1 输入 复制 15 6 550 23 0 0 输出 复制 7 470

我写的代码

#include<bits/stdc++.h>
using namespace std;
int cb[10000];
int main()
{
	int n,m;
	while(~scanf("%d %d",&n,&m))
	{
		int ans = 0;
		memset(cb,0,sizeof(cb));
		int cut = 0;
		if(n == m && n == 0)break;
		for(int i=1,j=1,k=0,l=0; k!=1000000 ; i++,j++,k++){
//		k总计数,i下标,j看是否为m整除,l统计已被记录的数量 
			if(i == n+1)i = 1;
			if(cb[i] == 1){//被标记则跳过 
				j--;
				continue;
			}
			if(j % m == 0){
				l++;
				if(l==n){
					ans = i;
				}
//				printf(" *%d* ",i);
				cb[i] = 1;//被标记
			}
		}
		int qq = 0;
		for(int i=1 ; i<=n ; i++){//查看有无未被记录的 
			if(cb[i] == 0){
				printf("%d\n",i);
				qq = 1;
				break;
			}
		}
//		printf("ans = %d\n",ans);
		if(qq == 0){//全部有 ,就输出最后一个 
			printf("%d\n",ans);
		}
	}
}

别人的代码

#include <iostream>
using namespace std;
const int m = 3;
int main()
{
    int n,m, f = 0;
    while(cin >> n >> m)
    {
        if(n +m == 0) break;
     
    for (int i = 1; i <= n; i++)
    f = (f + m) % i;
    cout << f + 1 << endl;
    }
}

代码来源: https://ac.nowcoder.com/acm/contest/view-submission?submissionId=45134874

约瑟夫环问题

我写的代码其实有一些问题,但能通过测评,看着别人的代码,感觉差距不小

用模拟来跑在大数据量的情况下占用时间和空间,不是很好的解法

其实对于约瑟夫环问题有着递推公式

图源自https://blog.csdn.net/u011500062/article/details/72855826![这里是引用](https://img-blog.csdnimg.cn/202010030012084.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0R1ZXNlcg==,size_16,color_FFFFFF,t_70#pic_center)

看图可以比较清楚直观的看出,我们的最后一位留下的是7 这时候它的下标是0 递推公式就是将这个过程反过来 每一轮去掉一位,然后从下一位又开始计算m,相当于是把下标前移了m位,每一轮重复这个过程,直到最后剩下的那个下标为0 反过来就是刚开始的那个下标为0,然后不断的循环从0开始按照规律往后加下标,因为往后的话会溢出需要取模,于是,递推公式就变成了每一轮的f(N,M)=(f(N−1,M)+M)%n

用代码来表示就是

int cir(int n,int m)
{
	int p=0;
	for(int i=2;i<=n;i++)
	{
		p=(p+m)%i;
	}
	return p+1;//下标要再加1
}

参考: https://blog.csdn.net/weixin_38214171/article/details/80352921 https://www.cnblogs.com/whiterock/p/8158812.html https://blog.csdn.net/u011500062/article/details/72855826(这个非常容易理解)