题目链接:http://poj.org/problem?id=1012
题目大意:
约瑟夫环的一个扩展,2*k个人围一圈,前k个是好人,后k个是坏人。报到m的人就要死掉,然后重新开始报数。要求的是最小的m使得后k个人总是先死掉!
题目分析:
这道题真心很头疼的啊!约瑟夫环的问题就是很难解,而且比较难理解的啊。。
做法很简单,就是按照原先做约瑟夫环的方法,从k+1开始枚举m,找到最小的m。
公式是:t=(t+m-1)%(sum--);sum为当前的总人数。把所有人从0开始编号到2*k-1,这样每一次死掉的人就是第t个人(去掉上一轮出局的,从原本的那个0开始重新编号后的t号会死掉!),只要保证前k个t里面不出现小于k的数就可以了。
在本机上打个表再提交就可以保证不超时了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 int f[100]={0,2,7,5,30,169,441,1872,7632,1740,93313,459901,1358657,2504881}; 6 int k; 7 int t; 8 bool ok(int m) 9 { 10 t=0; 11 int sum=2*k; 12 for(int i=1;i<=k;i++) 13 { 14 t=(t+m-1)%sum; 15 sum--; 16 if(t<k) 17 { 18 return 0; 19 } 20 } 21 return 1; 22 } 23 int main() 24 { 25 //freopen("text.out","w",stdout); 26 // for(k=1;k<14;k++) 27 //{ 28 // int m=k+1; 29 // while(ok(m++)==0) 30 // {} 31 // cout<<m-1<<","; 32 // } 33 while(scanf("%d",&k)!=EOF && k) 34 { 35 cout<<f[k]<<endl; 36 } 37 return 0; 38 }