约瑟夫问题(有时也称为约瑟夫斯置换,是一个出现在计算机科学和数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环。又称“丢手绢问题”.)据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。 以上来自百度百科
约瑟夫问题是个很有名的问题:N个人围成一个圈,从第一个人开始报数,第M个人会被杀掉,最后一个人则为幸存者,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1。
题目:
一群猴子要选新猴王。新猴王的选择方法是:让N只候选猴子围成一圈,从某位置起顺序编号为1~N号。从第1号开始报数,每轮从1报到3,凡报到3的猴子即退出圈子,接着又从紧邻的下一只猴子开始同样的报数。如此不断循环,最后剩下的一只猴子就选为猴王。请问是原来第几号猴子当选猴王?
输入格式:
输入在一行中给一个正整数N(≤1000)。
输出格式:
在一行中输出当选猴王的编号。
输入样例:
11
输出样例:
7
20分的题最后只拿了17分,共4个测试点,有1个没过,过段时间再回头来找找原因,现附上队友20分的满分解答(要学习她的写代码的简洁明了,
有些可以省去{}的地方就要省去,
尤其要利用好while后()的作用,与答案变量相结合。
其次,要注意判断顺序的问题!!!
#include <bits/stdc++.h>//万能头文件
using namespace std;
int main()
{
int n,top = 0,count = 0,s = 0;//top用于标记每轮循环猴子的位置 ,count用于标记报数,s用于记录被淘汰的猴子的个数
int a[1005] ={0};
cin >> n;
while(s != n-1)//先决条件,即此种做法不用再将N=1的情况单列出来
{
top++;
if(top > n) top = 1;//先令top自加,若超出位置,说明要进行下一轮循环
if(a[top] == 0) count++;
if(count == 3)
{
a[top] = 1;
count = 0;//当循环到3时,说明要再次从1开始报数
s++;
}
}
for(int i = 1;i <= n;i++)
{
if(a[i] == 0) cout << i;
}
}
然后是17分的答案
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
int N,cnt=0,t,ans;
cin >> N;
int mark[1005]={0};//mark数组作为标记,未被踢出的标记为0
t=1;
if(N!=1)
{
for(int i=1;;i++)
{
if(mark[t]!=0)
{
i--;
}//若被踢出,直接跳过
if(i%3==0&&mark[t]==0)
{
mark[t]=1;
cnt++;
}//每当轮到3的倍数,说明该报3了
t++;
if (t==N+1)
{
t=1;
}//开始新一轮循环
if(cnt==N-1)
{
break;
}
for(int i=1;i<=N;i++)
{
if(mark[i]==0)
{
ans=i;
}
}//寻找剩余的那只猴子
}
cout<<ans;
}
else
{
cout << "1";
}//我这种方法要单独讨论1是因为,我是先剔除再判断是否满足cnt==N-1
}