约瑟夫环问题。特化为前K个好人,后K个坏人。求前K轮杀掉所有K个坏人的最小M。
编号从0-N-1。共N个节点。
最关键的递推式F[i] (i从1开始) 表示第i轮杀掉的人的序数。
F[i] = (F[i-1]+m-1)%(N-i+1)。
这个F[i]是当前这轮的序数。杀掉之后,后面如果排有人则全部向前挪一个位置。
比如K=3,M=5:
第一轮:0 1 2 3 4 5 F[1] = 4
第二轮:0 1 2 3 5 F[2] = (4+5-1)%5 = 3
第三轮:0 1 2 5 F[3] = (3+5-1)%4 = 3 杀掉第3个人,编号为5。
这题我们只需要保证前K轮中每次杀掉的人的序号>=K 即可。这样每次杀掉一个人,前K个人的序数和编号都是不变的。
关于这个递推式,可以拆开来理解。F[i] = F[i-1]%(N-i+1) +(m-1)%(N-i+1)。
前半部分含义是之前一轮被杀掉的人由这一轮的谁代替。比如第三轮,F[2]%4 = 3,表示上一轮被杀掉的第3个人由这一轮的第3个代替,这一轮第3个编号为5。
后半部分含义是以代替的人开始向后跳过M-1个人。
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <list>
#include <set>
#include <time.h>
#include <string.h>
#include <string>
#include <iostream>
#include <map>
#include <queue>
using namespace std;
int n;
int m;
int result[15];
int main(){
int k;
while(scanf("%d",&k),k!=0){
if(result[k]){
printf("%d\n",result[k]);
continue;
}
m=1;
n = 2*k;
int res = 0;
for(int i=1;i<=k;++i){
res = (res+m-1)%(n-i+1);
if(res < k){
i = 0;
res = 0;
++m;
}
}
result[k] = m;
printf("%d\n", m);
}
//system("pause");
return 0;
}