POJ 1012 Joseph
2011-03-18 20:32
363 查看
考验思维能力的一道题
一开始用了最笨的方法,一个一个数,结果k到10就跑不出来了
后来看了discuss,可以推公式,这样就可以直接推得下一个杀人的位置,不必一个一个数了,时间可以节省非常多,自己找了小点的k尝试了下,推出了公式,我们从点1开始编号,则初始情况一共有2*k个点
假设b为已经杀掉的人数,now为现在的起始位置,next为下一个杀掉人的编号,初始时,b=now=0
则第一步,next=(0+m-1)%(2k-0)+1,(减1取模后再加1,为了防止0的出现),编号为next的人被杀掉,注意,此时的now不是next,而是next-1!然后再循环找下去就行,next=(now+m-1)%(2*k-b),由于不需要知道被杀掉的人原来的编号,杀掉这个人后,我们可以把整个环的数量减1,而所有坏人和好人都是还是各自连在一起的,所以不会有影响
后来看了discuss后,经牛人点拨,得知m必定为k+1的整数倍或者k+1的整数倍加1,为什么呢?考虑只剩下两个坏人时,他们此时的编号为k+1和k+2,如果杀掉的是k+1,那么走m=n*(k+1)+1步后可以杀掉原来编号为k+2的人,而如果先杀掉的是原来编号为k+2的,那么走m=n*(k+1)步后可以杀掉原来编号为k+1的人。这个解释太精彩了!这样优化后,可以从200多ms跑到100ms左右
总结:做题就是这样的,先从最笨的方法开始,然后在此基础上进行优化,另外,对于一些规律性的东西,可以从特殊情况或者最简单的情况去挖掘信息!还有,这题有很多组测试数据,但最多13种情况,我们可以将某种情况算出来的结果保存下来,下次再测试时直接输出!
代码:
一开始用了最笨的方法,一个一个数,结果k到10就跑不出来了
后来看了discuss,可以推公式,这样就可以直接推得下一个杀人的位置,不必一个一个数了,时间可以节省非常多,自己找了小点的k尝试了下,推出了公式,我们从点1开始编号,则初始情况一共有2*k个点
假设b为已经杀掉的人数,now为现在的起始位置,next为下一个杀掉人的编号,初始时,b=now=0
则第一步,next=(0+m-1)%(2k-0)+1,(减1取模后再加1,为了防止0的出现),编号为next的人被杀掉,注意,此时的now不是next,而是next-1!然后再循环找下去就行,next=(now+m-1)%(2*k-b),由于不需要知道被杀掉的人原来的编号,杀掉这个人后,我们可以把整个环的数量减1,而所有坏人和好人都是还是各自连在一起的,所以不会有影响
后来看了discuss后,经牛人点拨,得知m必定为k+1的整数倍或者k+1的整数倍加1,为什么呢?考虑只剩下两个坏人时,他们此时的编号为k+1和k+2,如果杀掉的是k+1,那么走m=n*(k+1)+1步后可以杀掉原来编号为k+2的人,而如果先杀掉的是原来编号为k+2的,那么走m=n*(k+1)步后可以杀掉原来编号为k+1的人。这个解释太精彩了!这样优化后,可以从200多ms跑到100ms左右
总结:做题就是这样的,先从最笨的方法开始,然后在此基础上进行优化,另外,对于一些规律性的东西,可以从特殊情况或者最简单的情况去挖掘信息!还有,这题有很多组测试数据,但最多13种情况,我们可以将某种情况算出来的结果保存下来,下次再测试时直接输出!
代码:
#include<iostream> #include<memory.h> #include<string> #include<cstdio> #include<algorithm> #include<math.h> #include<stack> #include<queue> using namespace std; int f[100]; bool go(int m,int k) { int i,j,cnt,now,next,b=0; cnt=j=0; i=-1; now=0; while(true) { //cout<<"now="<<now<<endl; next=(now+m-1)%(2*k-b)+1; //cout<<"next="<<next<<endl; if(next<=k) return false; else { now=next-1;//注意,杀掉的人被删除了,起点要减1 b++;//删掉的人数加1 cnt++; if(cnt==k) return true; } } } int main() { int i,j,cnt,k,m,flag; memset(f,0,sizeof(f)); while(scanf("%d",&k)!=EOF) { if(!k) break; if(f[k]) { cout<<f[k]<<endl; continue; } for(m=k+1;;m++) { //int t=m%(2*k);//m=i*(2*k)+j,i为整数,k<j<=2*k if(m%(k+1)>1)//m为k+1的整数倍,或者k+1的整数倍加1 continue; //if(t&&t<=k) //continue; if(go(m,k)) break; //if(t==0) //m+=k; } f[k]=m; cout<<m<<endl; } return 0; }
相关文章推荐
- POJ1012 Joseph
- POJ 1012 Joseph(打表题)
- poj 1012 Joseph (约瑟夫问题)
- poj 1012 Joseph (约瑟夫问题)
- POJ 1012 Joseph
- poj 1012 Joseph(约瑟夫环求每次出圈人的序号)
- POJ - 1012 joseph (约瑟夫打表)
- 【原】 POJ 1012 Joseph 约瑟夫 解题报告
- poj1012-Joseph(输出出列编号模板)
- POJ 1012 joseph
- poj 1012 joseph
- [POJ 1012] Joseph(约瑟夫)
- POJ 1012 Joseph
- poj 1012 Joseph(约瑟夫环)
- POJ-1012 Joseph
- POJ 1012 Joseph
- Poj 1012 Joseph (约瑟夫环)
- [POJ1012]Joseph
- POJ 1012 Joseph题解与心得
- Poj 1012 Joseph