这几天没事做的时候都会上projecteuler.net上面去做题,其中14题是这样的:
he following iterative sequence is defined for the set of positive integers:
n
n
/2 (n
is even)
n
3n
+ 1 (n
is odd)
Using the rule above and starting with 13, we generate the following sequence:
It can be seen that this sequence (starting at 13 and finishing at
1) contains 10 terms. Although it has not been proved yet (Collatz
Problem), it is thought that all starting numbers finish at 1.
Which starting number, under one million, produces the longest chain?
题目并不难理解,这个据说是著名的角谷猜想,现在要找到100万以下的数字中展开这个链最长的数字是多少。如果我一开始就直接按照题意来解答,这个题目花不了几分钟,直接暴力法。然而我却想的太多了,我猜想在计算这个链条长度的过程中会不会有很多数字会重复计算,如果加上缓存
以前计算的结果是否能节约比较多的时间?那么第一次解答如下:
<!---->#include
<
iostream
>
#include
<
map
>
#include
<
windows.h
>
using
namespace
std;
unsigned
long
produce_term(unsigned
long
n)
{
if
(n
&
1
)
return
3
*
n
+
1
;
else
return
n
>>
1
;
}
int
main()
{
map
<
unsigned
long
,
int
>
counters;
int
max_i
=
0
;
int
max_count
=
0
;
DWORD tick1,tickPassed;
tick1
=
GetTickCount();
for
(
int
i
=
1
;i
<
1000000
;i
++
)
{
int
sum
=
2
;
unsigned
long
term
=
i;
while
((term
=
produce_term(term))
!=
1
)
{
if
(counters[term]){
sum
+=
counters[term];
break
;
}
else
sum
+=
1
;
}
if
(sum
>
max_count)
{
max_i
=
i;
max_count
=
sum;
counters[i]
=
sum;
}
}
tickPassed
=
GetTickCount()
-
tick1;
cout
<<
tickPassed
<<
endl;
cout
<<
max_i
<<
endl
<<
max_count
<<
endl;
return
0
;
}
遗憾的是,这个版本跑了快13分钟,太让人难以接受了。那么是否能优化下?怎么优化?我的机器是双核的,跑这个单进程单线程的程序只利用了一半的CPU,那么能不能搞成两个线程
来计算?缓存需要在两个线程之间做同步,显然读的多,写的少,应该采用读写锁
。OK,第二个版本利用ACE的线程封装实现如下:
<!---->#include
<
iostream
>
#include
<
map
>
#include
"
ace/Thread_mutex.h
"
#include
"
ace/Synch.h
"
#include
"
ace/Thread_Manager.h
"
using
namespace
std;
class
ThreadSafeMap
{
public
:
ThreadSafeMap()
{
}
int
get
(unsigned
long
n)
{
ACE_READ_GUARD_RETURN(ACE_RW_Thread_Mutex,guard,mutex_,
0
);
return
counters_[n];
}
int
put(unsigned
long
key,
int
value)
{
ACE_WRITE_GUARD_RETURN(ACE_RW_Thread_Mutex,guard,mutex_,
-
1
);
counters_[key]
=
value;
return
0
;
}
private
:
map
<
unsigned
long
,
int
>
counters_;
ACE_RW_Thread_Mutex mutex_;
};
unsigned
long
produce_term(unsigned
long
n)
{
if
(n
&
1
)
return
3
*
n
+
1
;
else
return
n
>>
1
;
}
static
ThreadSafeMap counters;
ACE_THR_FUNC_RETURN run_svc (
void
*
arg)
{
int
max_i
=
0
;
int
max_count
=
0
;
for
(
int
i
=
500001
;i
<
1000000
;i
++
)
{
int
sum
=
2
;
unsigned
long
term
=
i;
while
((term
=
produce_term(term))
!=
1
)
{
if
(counters.
get
(term)){
sum
+=
counters.
get
(term);
break
;
}
else
sum
+=
1
;
}
if
(sum
>
max_count)
{
max_i
=
i;
max_count
=
sum;
counters.put(i,sum);
}
}
cout
<<
max_i
<<
endl
<<
max_count
<<
endl;
return
0
;
}
int
main(
int
ac,
char
*
argv[])
{
if
(ACE_Thread_Manager::instance ()
->
spawn (
//
Pointer to function entry point.
run_svc,
//
<run_svc> parameter.
NULL,
THR_DETACHED
|
THR_SCOPE_SYSTEM)
==
-
1
)
return
-
1
;
int
max_i
=
0
;
int
max_count
=
0
;
for
(
int
i
=
1
;i
<
500000
;i
++
)
{
int
sum
=
2
;
unsigned
long
term
=
i;
while
((term
=
produce_term(term))
!=
1
)
{
if
(counters.
get
(term)){
sum
+=
counters.
get
(term);
break
;
}
else
sum
+=
1
;
}
if
(sum
>
max_count)
{
max_i
=
i;
max_count
=
sum;
counters.put(i,sum);
}
}
cout
<<
max_i
<<
endl
<<
max_count
<<
endl;
return
ACE_Thread_Manager::instance ()
->
wait ();
}
将数据分成了两半,利用两个线程来计算,果然快了一点,快了多少呢?从13分钟减少到9分钟,CPU利用率也到了100%,内存占用也降低了一半,似乎成绩不错呀。正在沾沾自喜之际,突然想起,能不能简单地暴力破解,咱不搞缓存,不搞多线程,看看效果怎么样。那么第三个版本简单实现如下:
<!---->#include
<
iostream
>
using
namespace
std;
unsigned
long
produce_term(unsigned
long
n)
{
if
(n
&
1
)
return
3
*
n
+
1
;
else
return
n
>>
1
;
}
int
main()
{
int
max_i;
int
max_count
=
0
;
for
(
int
i
=
1
;i
<
1000000
;i
++
)
{
int
count
=
2
;
unsigned
long
term
=
i;
while
((term
=
produce_term(term))
>
1
)
count
+=
1
;
if
(count
>
max_count){
max_i
=
i;
max_count
=
count;
}
}
cout
<<
max_i
<<
endl
<<
max_count
<<
endl;
system(
"
pause
"
);
return
0
;
}
程序执行的结果让我惊掉了下巴,竟然只执行了1秒多,换成java也是一样。什么缓存、多线程,全抛到了九霄云外。
总结教训,想当然的性能估计是愚不可及的,想当然的优化是愚不可及的,简单直接才是美!
分享到:
相关推荐
正如中国谚语所说:“不确定性让人不安,但确定性则令人可笑。”在实际应用中,我们无法获得完全确定的信息,因此如何在不确定性环境下做出最优决策成为了一个重要的问题。 #### 鲁棒优化的基本概念 鲁棒优化的...
华三无线优化配置指导书主要包含了一系列针对WLAN网络的优化配置措施,旨在提升无线网络的性能和用户体验。以下是对文档中提到的各个配置知识点的详细解释。 1. WLAN网络调优简介 WLAN网络调优是指对无线局域网进行...
创建可笑的快速Lexers徽标创建可笑的快速Lexers。 徽标有两个目标:使创建Lexer变得容易,因此您可以专注于更复杂的问题。 要使生成的Lexer比您用手编写的任何内容都要快。 为了实现这些目标,徽标:将所有令牌定义...
网上的SQL优化的文章实在是很多,说实在的,我也曾经到处找这样的文章,什么不要使用IN了,什么OR了,什么AND了,很多很多,还有很多人拿出仅几S甚至几MS的时间差的例子来证明着什么(有点可笑),让许多人不知道其是...
再者,"可笑的快速"可能暗示了该库使用了一些高效的算法或优化技巧,使得即使在处理大量滚轮事件时也能保持流畅性,不会对页面性能造成显著影响。 最后,项目名为"MouseWheel-master",其中"master"通常代表项目的...
从给定的文件信息来看,主要讨论的是在JSP学生信息管理...正确使用`equals`方法、合理选择循环结构、掌握数据库查询与结果集处理,以及利用AJAX技术优化用户体验,都是构建高效、安全的学生信息管理系统的必要条件。
Crux这个名字在英语中有关键、核心之意,暗示了这些扩展对于优化Emacs工作流程的重要性。 Crux的扩展覆盖了编辑、导航、代码补全、项目管理等多个方面,旨在提高生产力,减少不必要的操作。下面我们将深入探讨其中...
它的设计使其外观和行为类似于标准系统控件,并进行了优化以确保对滚动性能的影响最小。特征允许对UIScrollView的整个内容高度进行细粒度的滚动。 通过Objective-C运行时和KVO直接与UIScrollView互操作。 与标准...
【优化方案】(山东专用)高中英语 Unit1 SectionⅠ Warming Up & Reading Preparing精品课件 新人教版选修6,这个标题表明我们正在探讨一个针对山东省高中英语教学的优化方案,主要集中在Unit1的SectionⅠ,即...
React Storefront框架...可笑的速度React Storefront付出了更多努力,以从所有可能的实际和用户感知的性能优化中挤出速度,包括: 动态数据的高速缓存命中率高服务器端渲染自动创建AMP 动态数据的预测性预取代码拆分缓
"小小码童,可笑可笑"这句描述可能暗示了该项目起始于作者初学编程时的基础阶段,但随着时间的推移,它已经发展成为一个相对完整的框架,用于展示Java的高级应用。 在Java编程中,进阶学习通常涉及到以下几个方面:...
假如企业不管4C只是、一味地强4调4P理论,那就是在闭门造车,一定会制订出可笑的销售政策、可笑的产品、可笑的促销计划;假如企业只是、一味地站在消费者的角度进行4C的时候,来满意消费者的需求,企业的成本将会...
例如,它提供了更强大的性能优化,如回收视图(view recycling)机制,减少内存占用和提高滚动流畅性。同时,RecyclerView支持多种布局管理器,如线性布局(LinearLayoutManager)、网格布局(GridLayoutManager)和...
在教学目标方面,学生需要整体感知课文,理解阿长的人物形象,包括她的饶舌多事、规矩繁多、爽朗热心、乐于助人的性格特征,以及她的无知可笑、愚昧落后和淳朴善良、仁慈的美德。同时,学生应学会通过领会文章中的...
描述中的"可笑的"可能是在描述漫画内容的幽默性质,或者是在开发过程中遇到了一些令人啼笑皆非的问题。结合标签"JavaScript",我们可以推测这是一个使用JavaScript技术来创建的Web应用,可能是用于展示漫画、制作...
在描述中提到的"可笑的",虽然在中文里主要表达一种幽默或滑稽的感觉,但在IT语境下,这可能是对设计或交互性的形容,比如一个具有趣味性、引人发笑的漫画网站或应用。这可能涉及到如何通过HTML的特性,如CSS...
通过使用Photoshop CC的工具,用户可以轻松地将不同人的面部特征进行交换或组合,创造出一系列滑稽可笑的形象。这项技巧不仅可以用来增加乐趣,还能帮助设计师探索不同人物造型的可能性。 ##### 通过色调调整改变...
作者邀请读者发现并纠正可能存在的错误,这种开放态度有助于资源的不断完善和优化,使之成为更加宝贵的备考资料。这种互动交流的方式不仅促进了知识的共享,也激发了社区内成员的学习热情和互助精神,共同构建了一个...
随着技术的发展,深度卷积神经网络通过增加网络层数、扩大训练数据集规模以及优化网络结构和训练算法,逐步提升了模型的性能。例如,AlexNet、ZF-Net、VGG、GoogleNet和ResNet等经典网络结构不断挑战深度的极限,...