再说约瑟夫环
2015-07-09 13:12
246 查看
题目来自@陈利人的微博:1到n个人排成一圈,从编号为1的人开始,依次说白,黑,白,黑,。。。,说到黑的人离队,问最后留下编号为几的人。
大家都知道,这是非常典型的约瑟夫环问题。其一般形式是M个人,构成一个环(圆),每隔N人就滚蛋,问最后剩下谁。
很多同学说答案是1,这可能是因为没理解题目(没上过数据结构?)。比如说三个人,A、B、C,编号分别是1、2、3.
A说“白”,B说“黑”,C说“白”,然后B滚蛋了,那么剩下A、C。注意,C已经说”白“了,而大家是构成环的,所以A要说“黑”了,所以A滚蛋。最终剩下编号为3的C。
通过一个循环链表(队列)可以很方便的模拟。代码我就不写了。模拟,是ACM题目训练里的三大常见题型之一:模拟、数论、DP、贪心、字符串、搜索
通过分析(大家可以参考这个链接:http://www.zhihu.com/question/20065611或者参考离散数学教材),可以通过简单的循环左移一位来获得结果,复杂度为O(1)。
比如说n=5,那么二进制表示为101,循环左移一位变成011,也就说如果n=5,那么最终唯一剩下来的编号是3(011)
但是,这里需要特别注意前导0的存在。比如n=5,那么二进制00000101循环移位后得到00001010结果却是10,这明显是不对的。
说明:
1,我最早知道循环移位可以解决这个问题,是在高中时候所看的《算法设计与分析基础》(Anany Levitin著)这本书。有兴趣朋友可以参考下。
2,我最早知道代码中获得前导0的数量的实现,是在本科图书馆里看的《Hacker's Delight》(Henry S. Warren著)这本书。有兴趣朋友可以参考下。
当然,估计很多编译器和CPU都有搭配类似的指令了,速度当然很快。
大家都知道,这是非常典型的约瑟夫环问题。其一般形式是M个人,构成一个环(圆),每隔N人就滚蛋,问最后剩下谁。
很多同学说答案是1,这可能是因为没理解题目(没上过数据结构?)。比如说三个人,A、B、C,编号分别是1、2、3.
A说“白”,B说“黑”,C说“白”,然后B滚蛋了,那么剩下A、C。注意,C已经说”白“了,而大家是构成环的,所以A要说“黑”了,所以A滚蛋。最终剩下编号为3的C。
通过一个循环链表(队列)可以很方便的模拟。代码我就不写了。模拟,是ACM题目训练里的三大常见题型之一:模拟、数论、DP、贪心、字符串、搜索
通过分析(大家可以参考这个链接:http://www.zhihu.com/question/20065611或者参考离散数学教材),可以通过简单的循环左移一位来获得结果,复杂度为O(1)。
比如说n=5,那么二进制表示为101,循环左移一位变成011,也就说如果n=5,那么最终唯一剩下来的编号是3(011)
但是,这里需要特别注意前导0的存在。比如n=5,那么二进制00000101循环移位后得到00001010结果却是10,这明显是不对的。
#include<iostream> using namespace std; const int BASE = 32; int getLeadingZeroCounts(unsigned int x) { int n = 1; if (x == 0) return -1; if ((x >> 16) == 0) { n = n + 16; x = x << 16; } if ((x >> 24) == 0) { n = n + 8; x = x << 8; } if ((x >> 28) == 0) { n = n + 4; x = x << 4; } if ((x >> 30) == 0) { n = n + 2; x = x << 2; } n = n - (x >> 31); return n; } unsigned int get(unsigned int n) { unsigned int temp1 = (1 << (BASE - getLeadingZeroCounts(n)))-1; unsigned int temp2= n << 1; unsigned int temp3 = temp1 & temp2; return temp3 | 1; } int main() { unsigned int n; while (cin >> n) { cout <<get(n) << endl; } }
说明:
1,我最早知道循环移位可以解决这个问题,是在高中时候所看的《算法设计与分析基础》(Anany Levitin著)这本书。有兴趣朋友可以参考下。
2,我最早知道代码中获得前导0的数量的实现,是在本科图书馆里看的《Hacker's Delight》(Henry S. Warren著)这本书。有兴趣朋友可以参考下。
当然,估计很多编译器和CPU都有搭配类似的指令了,速度当然很快。
相关文章推荐
- WPF 多语言
- Python发邮件
- iOS添加日期选择器
- 解题报告:线段树的查询
- 安卓卸载一个程序的代码
- C# 中的委托和事件(通俗易懂)
- html 学习笔记2
- HDU 5072 Coprime (单色三角形+容斥原理)
- 百度地图页面上展示
- GRE写作必备句型
- 6.2-1
- Chrome Dev Tool 中时间线各阶段代表的意义
- 转载Mysql的乱码问题
- 关于心理的二十五种倾向(查理·芒格)-1
- MySQL与Oracle 差异比较之数据类型比较
- JavaScript编码规范-Baidu
- 华为 Hybrid-vlan配置,将接口批量加入vlan,配置详解
- ORA-16179: incremental changes to "log_archive_dest_1" not allowed with SPFILE
- smack on android SSL设置记录之学习用keytool生成证书
- register_shutdown_function函数详解