/* 功能Function Description: 约瑟夫环+枚举 POJ-1012 开发环境Environment: DEV C++ 4.9.9.1 技术特点Technique: 版本Version: 作者Author: 可笑痴狂 日期Date: 20120731 备注Notes: 大致题意: 有k个坏人k个好人坐成一圈,前k个为好人(编号1~k),后k个为坏人(编号k+1~2k) 现在有一个报数m,从编号为1的人开始报数,报到m的人就要自动死去。 问当m为什么值时,可以使得在出现好人死亡之前,k个坏人先全部死掉? PS:当前一轮第m个人死去后,下一轮的编号为1的人 为 前一轮编号为m+1的人 前一轮恰好是最后一个人死掉,则下一轮循环回到开头那个人报“1” */ /* //代码一:用顺序表实现---枚举( 超时TLE) #include<stdio.h> #include<malloc.h> int main() { int *base; int i,k,j,t,flag,sum; while(scanf("%d",&k),k) { base=(int *)malloc((2*k)*sizeof(int)); flag=1; for(i=k+1;flag;++i) //从k+1开始向后枚举 { sum=k*2; //sum 存储总人数 for(t=0;t<2*k;++t) //每次都要重新初始化 base[t]=t+1; for(j=(i-1)%sum;;) //j存储每次去除的人的下标 { if(base[j]<=k) break; for(t=j+1;t<sum;++t) //删除该节点---后边元素依此前移 base[t-1]=base[t]; --sum; if(sum==k) { flag=0; printf("%d\n",i); break; } j=(j+i-1)%sum; } } free(base); } return 0; } */ /* //代码二:把代码一中打表(AC) #include<stdio.h> int main() { int k; int Joseph[14]={0,2,7,5,30,169,441,1872,7632,1740,93313,459901,1358657,2504881}; while(scanf("%d",&k),k) printf("%d\n",Joseph[k]); return 0; } */ //代码三:用数学方法递推 //出处:http://blog.csdn.net/lyy289065406/article/details/6648444 /* 递推公式为: ans[i]; //第i轮杀掉 对应当前轮的编号为ans[i]的人 ans[0]=0; ans[i]=(ans[i-1]+m-1)%(n-i+1); (i>1 , 总人数n=2k 则n-i为第i轮剩余的人数) */ //Memory Time //184K 250MS #include<iostream> using namespace std; int main(void) { int Joseph[14]={0}; //打表,保存各个k值对应的m值 int k; while(cin>>k) { if(!k) break; if(Joseph[k]) { cout<<Joseph[k]<<endl; continue; } int n=2*k; //总人数 int ans[30]={0}; //第i轮杀掉 对应当前轮的编号为ans[i]的人 //PS:每一轮都以报数为“1”的人开始重新编号 int m=1; //所求的最少的报数 for(int i=1;i<=k;i++) //轮数 { ans[i]=(ans[i-1]+m-1)%(n-i+1); //n-i为剩余的人数 if(ans[i]<k) //把好人杀掉了,m值不是所求 { i=0; m++; //枚举m值 } } Joseph[k]=m; cout<<m<<endl; } return 0; }