QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 4108|回复: 0
打印 上一主题 下一主题

算法入门系列之二 -- 筛选法

[复制链接]
字体大小: 正常 放大

7

主题

1

听众

43

积分

升级  40%

该用户从未签到

新人进步奖

跳转到指定楼层
1#
发表于 2004-6-8 16:42 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
所谓筛选法就是从全集中将不合格的项全部删去,剩下的就是答案。% b) {3 T3 Q9 R: b3 l4 v4 v. k( [. D

* C3 H1 s; e9 V+ Y7 h2 O& P1: 求1-100之间的质数3 o$ _$ A0 |1 R% n3 j  b0 X: U: V
2 C0 w+ Y% e6 Z- Y0 X* e: X& \: ^
    原理:先将2的倍数全部划掉,再将3的倍数全部划掉……直到将10的倍数全部划掉(10^2 = 100 )。剩下的就是质数.# h" j9 J5 l  g( ]
2 N& q; Y% g6 z& p- S
void fun1()9 `  @' Q) S6 h% D
{6 z$ G( P( A. P2 Z( [9 G
    int i, j;
0 a$ m# f: _' P' Y    bool flag[100];
- n0 o6 m% }. O2 B& e: z' b) p8 G
% D* ~- X0 |& x* h' j( s    for ( i = 2; i < 100; i++ )
# i. A! A" T" L) }        flag = true;% U" W' @# G( l. W

! }/ N7 e3 ]; [$ n    //下面开始划掉合数1 |- o, G9 J8 d7 Z) L7 P
    for ( i = 2; i < 10; i++ ) //因为合数的最小正因数不大于它的平方根
, G' ]1 K& q; A- n) `# N- {- k8 P    {
2 t8 H- g7 a  ]9 _        if ( flag == false )! y/ q4 [8 Y3 \0 ~6 @+ ]' a$ b) c
            continue; //既然i已经是合数,它的倍数应该已经被划掉
; l3 m) x. t3 s+ M4 J* L        for ( j = 2; j * i < 100; j++ )//划掉i*j
8 l) }( P1 b6 B2 T7 T            flag[i*j] = false;& x( e! y) q* H. X5 ^
    }) E! W# l/ P+ P) N
/ b  r4 A5 L9 x- _2 k+ ?
    //输出结果+ e/ s" D2 E7 h/ U9 ]' y! R
    for ( i = 2; i < 100; i++ )$ w2 K4 y( h  P8 w, `' s  Q
        if ( flag )
9 R) \+ U. n# g8 G3 b5 x            cout << i << ' ';
; t/ x) g+ b7 \4 p' E: I1 V" d( k9 H}1 _. b2 S/ |3 p9 B
$ h4 P# w. k" }2 N
2: 30个人站成一圈,从第一个人开始报数,凡报到5的拉出去毙了,剩下的人接着从1开始报,直到只剩一人放掉。想活命该站哪?1 L$ z" Q! M6 _; m4 Q& k8 Z

8 U& o% c- n8 X: \! ^    这是个经典问题,解法就是模拟整个过程,有点类似于循环队列。' K) ?' ]# }4 u8 m  Z- g7 c

" C* v, c+ N( I# M) \2 d    另外,为了程序上处理方便,可以假定所有的人都拉去毙了,然后看一下最后一个被毙掉的是谁。另一处为了处理方便而采取的措施是pos的初始值设为-1.很多时候,对问题的问法稍作变动,或者将初始值、加减变量的位置稍作调整,用程序处理起来会方便很多。
" \5 o; O7 C+ L; y+ k+ q
; A. z( T& _3 ^8 l) V; avoid fun2()
3 \5 `/ l& H: C# G0 `4 W+ J" V/ z{
) w% s, v: s- ^% n    bool flag[30];//标记第i个人的状态,false已被毙掉,true还没被毙掉
! ^9 q* B0 Z) ~" n0 h% i
/ C6 L* n' O6 S! x2 y    for ( int i=0; i< 30; i++ )) D/ S' c! H9 G/ ]. K
        flag = true;
; ^, t# A) ], Y
/ y1 b9 V' Y- f    int n = 30;//还剩几个人" T# ~6 A' a* o1 s+ J
    int cnt;
/ m: @/ p; j: F, A/ B    int pos = -1;//初始值不一定从0开始,设为-1处理起来较方便
: D/ t' l7 s1 }7 [# @    while ( n > 0 )
+ t8 p2 u* v, M5 n4 B6 k( C4 G2 n    {6 @% }6 I# x& r: d2 ?
        cnt = 0;
8 ?, b+ u7 a# F3 c! j+ }/ M6 [0 d        while ( cnt < 5 )
: K- {# s4 v( c3 [% f6 N, }  [        {
$ a  J  h% L9 O, s, W5 s  o' a            if ( ++pos == 30 )% \5 t, i  ~* O) K  k2 o" G: Z
                pos = 0;
7 m% [" a% \: F: J) L            if ( flag[pos] )//此人还没被毙掉
+ `; N, Y" o7 D' E9 l+ u9 ~! q0 D1 K                cnt ++;/ \! i, Y+ E* Y" w- E6 ~
        }
) e  M9 o! k& P9 M+ b* ?$ \: H' @; X        //退出时cnt == 5,pos指向报5的人
. S2 M& l/ I$ ^        flag[pos] = false;//毙掉. F5 C( s  z& \4 z4 h% O( f
        n --;//剩余人数减1
: m6 y9 @* Y  `% l# G: ?2 j    }
# `# }) F' c9 z* z. M: y    //最后一个被毙的就是幸存者2 ^2 L6 _0 u" n) i1 K6 q) G" x# h
    //之所以加1是因为程序中从0开始计数,输出却以1开始计数3 L5 Q8 R- P5 b& I# C% |, ^/ Y1 Q& U
    cout << pos + 1 << ' ';/ N$ S' s6 K# e5 I! N; o
}1 W! Q. S$ z( `! f" C3 l" O
2 H% Y% {7 F4 t5 B3 q$ T* N
3: 一个数被5除余3,被7除余2,求此数最小为几。
! c/ y* O3 J- [
/ ^! y; D$ ]; F' i2 O( @* f: I3 ]    筛选法不一定非要标记true/false,有时候也可以使用计数来进行筛选,这个问题就是一例。5 ^4 o# _# `1 L3 M) R- H
    首先,如果问题有解,则解必小于 5 * 7 = 35,只用在此范围内筛选即可。
, \. i  Y7 _. m- E: k    在程序处理上,如果一个数满足一个条件,就将计数值加1,最后计数值为3的即为所求。
4 W4 w/ G) ]- f4 Q  d& E7 c
& ], }, i6 R& y; u- x- Qvoid fun3()6 s6 q, \8 H# j$ b5 y8 r5 }- {
{
* D0 V3 ~9 n. K6 f0 Y6 W" q    int a[105];//105 = 5 * 7
- k2 [7 |% s2 x2 R& `. i2 j2 _    int i;
( l% w. M9 k0 M    //计数清0
: b% k/ _& S$ ?. U% w    for ( i = 0; i < 35; i++ )
" z& S8 H: x: M8 R% c) l        a = 0;
3 P3 Z; L' Y  j7 X9 R. {; ]    //开始筛选7 \6 _6 Z; {2 R
    for ( i = 3; i < 35; i += 5 )
" g2 W- ^0 ?" i% V" R3 X# l) ?        a ++;
% g% z: T2 h0 o' M1 ]7 M8 Y  ]    for ( i = 2; i < 35; i += 7 )! @3 B  n6 B4 V
        a ++;
" Q5 H5 t; f. R  a% ]
7 m  [# o  q! i, r. q    for ( i = 0; i < 35; i++ )
9 n+ ^% O& H1 E5 s& K        if ( a == 3 )
; h' x1 S9 U/ A/ T; \9 F: T, F        {
9 a; q. ?) K9 f4 H* C/ U            cout << i << endl;9 [- j* @* ?3 l( C# S
            return;" V6 y7 s9 [. _7 E+ Q* ^
        }
1 |- W2 v5 r, q    //如果执行到这里说明无解0 d7 v0 K; r- q% T9 y
    cout << "No Answer!" << endl;, Y2 _9 s5 G% a, F7 }, B, o
}; K( I: @5 t  h  {$ ?* {+ n
$ F* v  _- L1 f) h  G8 V* c, S8 L8 c- `

4 c7 e0 U: A8 C) ?总结:
0 j( ~  G0 H' k( O7 d5 J" |    筛选法的时间效率较高,但需要一个辅助数组,这就意味着对规模很大的问题不适用。例如第3个问题,条件多1个,需要的空间就翻几倍。解决的办法是:
. ], F- m$ _& l( Z9 f
( g( [5 Y# r& x3 Q' p& Bfor ( int i = 0; i< n; i++ )# C+ G3 p' w9 q4 Z7 c( y# c; h
{
/ r) w3 S8 D1 Q; t    if ( i % 5 == 3 && i % 7 == 2 && ... )0 f3 O9 w5 l, }) x
        cout << i;
, J$ n' `9 k0 C5 ~( o! x}
. W$ f: I' r7 y' ^- B# _    但相应的,这样做速度就慢了下来。所以还得根据问题的规模来决定使用什么方案。0 D( f& R( j" g+ x9 i/ F

" B+ ^3 b3 w' ~! z    总体来讲,对于可以条件判断较复杂,且根据前一个(不)符合条件的情况较简单的推出下一个(不)符合条件的情况,(不)符合条件的情况分布较稀疏的问题,用筛选法速度较快。如果第3题中加一个条件被2除余1,用筛选法就不太合算了。4 \: X, a. D7 ^# F3 B' z
1 t# F% ~) q! E6 D( [0 s4 A
    最后说明一下,此次给出的程序目的在于说明方法,在效率并不是最高的
zan
转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信
您需要登录后才可以回帖 登录 | 注册地址

qq
收缩
  • 电话咨询

  • 04714969085
fastpost

关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

手机版|Archiver| |繁體中文 手机客户端  

蒙公网安备 15010502000194号

Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

GMT+8, 2025-8-21 18:00 , Processed in 1.829514 second(s), 51 queries .

回顶部