这是一道约瑟夫环问题的变种,大致意思就是,有2*k个人围成一圈,第一次从编号为1的人开始报数,报到m的人退出,接下来继续从退出的后一个人开始从1开始报,报到m的人再退出,问当m设置为多少的时候,后k个人先退出,然后前k个人才会依次退出?
思路:只要涉及到算法的题,我一般都不会做。。这道题我咋一看就是约瑟夫环的问题,建议初次做这题的人先看一下基本的约瑟夫环的问题,这道题关键就是列出递递推式。
假设ans[i]表示第i轮退出编号为ans[i]的人,
那么ans[0] = 0
ans[i] = (ans[i-1]+m-1)%(n-i+1)
不要问我这个式子怎么推出来的,网上copy大牛的。。式子中前k个人编号为0~k-1
有了这个式子我们可以很快的求出每轮退出的人,只要判断前k个退出的人是不是含有编号1~k之间的人就可以了;
这里做一点时间上的优化,因为本题中k的值在1~14之间,所以我们可以建立一张记录表,将每次k的取值对应的m的值记录在数组里, 这样就可以避免重复计算。
#include <iostream>
using namespace std;
int main(){
int k;
int Joseph[14]; //记录表,将下标为k对应的m的值记录下来,避免重复计算
memset(Joseph,0,sizeof(Joseph));
while(cin>>k&&k){
int n = 2*k;
if(Joseph[k]){
cout<<Joseph[k]<<endl;
}
else{
for(int m=1;;m++){
int result = 0;
for(int i=1;i<=k;i++){ //用i表示第几轮
result = (result+m-1)%(n-i+1);
if(result<k)
break;
}
if(result>=k){
Joseph[k] = m; //找到符合条件的值,就更新记录表
cout<<m<<endl;
break;
}
}
}
}
return 0;
}