POJ_1781_In Danger_约瑟夫问题
2015-10-31 21:06
344 查看
这道题是约瑟夫问题的变形,大意就是给定很多人,围成一个环,从一开始数,每次杀死第三人,事实上按数据是每数到2就杀死当前的人。第一个样例中,一共五人,先杀死2号,之后是4号,然后1号,最后杀死5号,于是3号最后活下来了。
输入数据,读为字符型较方便,我是直接读一个字符串s,然后计算人数人数,这个人数很多,模拟的话一定会超时,但是模拟的方法先简述一下:
设有n个人,数到m杀死当前人。
定义一个布尔型数组记录人的生死,初始化为true,代表都活着。定义一个k=0,记录已经杀死几个人。一个变量t记录当前人的编号,x记录数到了几。
当k不等于n时,t每次加一,若t大于n;则令t=1。若通过布尔型数组判断编号为t的人还活着,x也加一。若x==m,令数组下标为t的值为false。那么最后的t值即为活下来的人。
核心代码(模拟):
然而对于这道题,需要找到一些规律,否则会超时。
那么假设n个人,每次杀死第m人时活下来的是编号为k的人,当m一定,对于n+1个人来说,第一个杀死的是编号为m的人,还剩下n人,那么这就和n个人的情况一样了,只是不是从第一个人开始数,而是从m+1开始。这样有n+1个人时,最终活下来的为第k+m号人。同理,n+2时,为k+2m号。
问题是k每次加m时,n只是加上1,可能会出现算出的活下来的人的编号大于n的情况,此时怎么办呢?显然,我们对算出的数对n取模即可。
这时对本题中m一直为2,对于n为2的整数次幂时,第一次转一圈杀死了所有的编号为偶数的人,然后又从1号开始,这时剩下n/2个人,人数还是2的整数次幂,不妨把这些人重新按顺序编号,又杀死了那些编号为偶数的一半人,依然回到1……最后显然回到n=2的情况,最终活下来的人为1号。所以,当n为2的整数次幂时,活下来的人是1号。
这样对于一个任意的n,若是2的整数次幂答案为1,。其他的只要找到不大于它的最大的2的整数次幂的数x,然后算出1+2(n-x)即为答案。那么关于这个值为什么必然小于下一个2的整数次幂数,下一个数为2x,n-x>x时,n>2x,不大于n的最大的2的整数次幂的数就是2x了。
AC代码
输入数据,读为字符型较方便,我是直接读一个字符串s,然后计算人数人数,这个人数很多,模拟的话一定会超时,但是模拟的方法先简述一下:
设有n个人,数到m杀死当前人。
定义一个布尔型数组记录人的生死,初始化为true,代表都活着。定义一个k=0,记录已经杀死几个人。一个变量t记录当前人的编号,x记录数到了几。
当k不等于n时,t每次加一,若t大于n;则令t=1。若通过布尔型数组判断编号为t的人还活着,x也加一。若x==m,令数组下标为t的值为false。那么最后的t值即为活下来的人。
核心代码(模拟):
memset (a,true,sizeof(a)); s=0,t=0,k=0; do { t++; if (t>n) t=1; if (a[t]==true) s++; if (s==m) { a[t]=false; s=0; k++; if(k==n) cout<<t<<endl; } }while (k!=n);
然而对于这道题,需要找到一些规律,否则会超时。
那么假设n个人,每次杀死第m人时活下来的是编号为k的人,当m一定,对于n+1个人来说,第一个杀死的是编号为m的人,还剩下n人,那么这就和n个人的情况一样了,只是不是从第一个人开始数,而是从m+1开始。这样有n+1个人时,最终活下来的为第k+m号人。同理,n+2时,为k+2m号。
问题是k每次加m时,n只是加上1,可能会出现算出的活下来的人的编号大于n的情况,此时怎么办呢?显然,我们对算出的数对n取模即可。
这时对本题中m一直为2,对于n为2的整数次幂时,第一次转一圈杀死了所有的编号为偶数的人,然后又从1号开始,这时剩下n/2个人,人数还是2的整数次幂,不妨把这些人重新按顺序编号,又杀死了那些编号为偶数的一半人,依然回到1……最后显然回到n=2的情况,最终活下来的人为1号。所以,当n为2的整数次幂时,活下来的人是1号。
这样对于一个任意的n,若是2的整数次幂答案为1,。其他的只要找到不大于它的最大的2的整数次幂的数x,然后算出1+2(n-x)即为答案。那么关于这个值为什么必然小于下一个2的整数次幂数,下一个数为2x,n-x>x时,n>2x,不大于n的最大的2的整数次幂的数就是2x了。
AC代码
#include<cstdio> #include<cstring> #include<iostream> using namespace std; long long p; int n,m,z; string s; long long ef[50]={0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456}; //数组打表记录2的整数次幂 int main() { while (cin>>s,s[0]-'0'+s[1]-'0') { n=s[0]-'0'; m=s[1]-'0'; z=s[3]-'0'; p=(n*10+m); for (int i=1;i<=z;i++) p*=10; if (p==1||p==2||p==4) { cout<<1<<endl; } else { if (p==3) cout<<3<<endl; else { long long t; int k; for (int i=1;p>ef[i];i++) k=i; if (ef[k+1]==p) cout<<1<<endl; else { t=1+2*(p-ef[k]); cout<<t<<endl; } } } } return 0; }
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- 解析C++中派生的概念以及派生类成员的访问属性
- C++ Custom Control控件向父窗体发送对应的消息