QQ登录

只需要一步,快速开始

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

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

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

7

主题

1

听众

43

积分

升级  40%

该用户从未签到

新人进步奖

跳转到指定楼层
1#
发表于 2004-6-8 16:42 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
所谓筛选法就是从全集中将不合格的项全部删去,剩下的就是答案。
/ K. b7 R9 K/ u5 T1 t1 T+ w& v9 }; I- V1 r- i) @6 v* V* \- A
1: 求1-100之间的质数
5 H  r" j& ?, D* l$ z6 D
1 c2 r! v: H3 s' j0 m    原理:先将2的倍数全部划掉,再将3的倍数全部划掉……直到将10的倍数全部划掉(10^2 = 100 )。剩下的就是质数.4 Y. z9 B7 h& J
5 Y6 `- v  Y6 V3 P) S* L6 F
void fun1()
7 u: |+ P6 y" \" f{
2 K4 j" H; [0 q% H: e    int i, j;
! y$ g0 L8 Y1 H$ w: P. t    bool flag[100];; c( ]) w+ y' W+ u

( h0 U, D( A5 ?* G4 \  k    for ( i = 2; i < 100; i++ )
( O( }, l6 T9 w        flag = true;
  O( h( O6 V5 @8 D1 g
) e& G# w7 X8 O, b4 D7 Y- i5 b/ p9 R    //下面开始划掉合数
# q- J5 B+ F+ o! D    for ( i = 2; i < 10; i++ ) //因为合数的最小正因数不大于它的平方根3 `: k8 a8 Q$ Z& p' H3 a
    {3 w* O6 e0 }, h9 Y5 V, q( f
        if ( flag == false )
- Q$ }5 V, l2 I6 `* ?            continue; //既然i已经是合数,它的倍数应该已经被划掉
+ f6 Y& l) ?: g' @8 k        for ( j = 2; j * i < 100; j++ )//划掉i*j
: I. i* B. j  Q; j# S            flag[i*j] = false;9 w0 T  J5 i) ^6 X0 ~/ j9 I! j) D
    }3 [$ j4 @; n7 [. {7 C$ i+ Z# x' r9 P

7 e1 ^. r1 W$ {- E4 d3 z    //输出结果/ d' }# K' h* n/ ?1 m
    for ( i = 2; i < 100; i++ )
4 b, V+ ]2 F1 ?, @1 ]        if ( flag )' {- l" d) |2 D$ h" j7 _4 ]
            cout << i << ' ';
5 C. d! \" b+ X1 X) a}  t! f1 ]9 V- b
2 T) Y" S0 K5 M) s5 |0 W
2: 30个人站成一圈,从第一个人开始报数,凡报到5的拉出去毙了,剩下的人接着从1开始报,直到只剩一人放掉。想活命该站哪?+ Y8 |+ ]7 S2 s1 W3 J
7 x1 @  ]* p2 L" X7 ?$ m
    这是个经典问题,解法就是模拟整个过程,有点类似于循环队列。" A- B: e- R; G, U

) K- a, K* A* ]# V$ l# x    另外,为了程序上处理方便,可以假定所有的人都拉去毙了,然后看一下最后一个被毙掉的是谁。另一处为了处理方便而采取的措施是pos的初始值设为-1.很多时候,对问题的问法稍作变动,或者将初始值、加减变量的位置稍作调整,用程序处理起来会方便很多。5 B5 d' f' R2 j! j

5 u, O! j7 J* A7 N0 e' ^: v4 qvoid fun2()/ R& F; ~, x# r9 o
{8 |: H. e5 C) e! @0 M$ l4 w
    bool flag[30];//标记第i个人的状态,false已被毙掉,true还没被毙掉9 c0 G# k! ~7 {7 X  I* ^: g8 H

& c! s4 I, \- s* r5 o, l    for ( int i=0; i< 30; i++ ). I+ r* X' v) U0 ?" r! R1 z$ z
        flag = true;
; v: T; T+ I+ {' u" N" c3 z7 y* J3 g
    int n = 30;//还剩几个人
  G% I5 [4 s- T) m" v7 ]    int cnt;# u3 w% _5 Z3 n( O
    int pos = -1;//初始值不一定从0开始,设为-1处理起来较方便
3 S6 i6 U3 T9 P2 {! ~    while ( n > 0 )
, x; t: C* l) p, }, h" R% X8 n    {
( d* _  Y+ v5 z( ~% S3 D5 E        cnt = 0;  C9 r9 X5 s$ G6 J( v
        while ( cnt < 5 )+ ^" U  w) q% @) I* I
        {# `4 Q! D7 I+ o0 o. G$ V% ?) V
            if ( ++pos == 30 )- j( G2 ^5 j6 x+ C4 T
                pos = 0;
7 k, l( s6 b. {, K- L1 l" j            if ( flag[pos] )//此人还没被毙掉
4 b) d; A7 O) @) a# X                cnt ++;
8 ]+ M6 \5 j; E! r( n. v7 S9 I        }2 S3 w9 z) b* V5 z* H0 y, \/ s+ u
        //退出时cnt == 5,pos指向报5的人
2 g8 i7 `: k+ X  J1 i2 y        flag[pos] = false;//毙掉- L! `4 q0 Z  y4 |6 r) G) g% U3 v
        n --;//剩余人数减1# b6 e1 L" f9 e# L
    }
- \9 |" D) W, `3 `0 _' M    //最后一个被毙的就是幸存者
( `. C+ ?3 h3 W    //之所以加1是因为程序中从0开始计数,输出却以1开始计数
) b$ M$ g; n- D& W$ D    cout << pos + 1 << ' ';
2 f$ ?+ l- k% i0 l. A3 Q6 M}
. k0 s% C9 M: T# t, V4 z2 |8 J" m, G
3: 一个数被5除余3,被7除余2,求此数最小为几。
2 ^5 o0 |; e+ Z0 \
( w6 k& ~- r/ g! l8 R    筛选法不一定非要标记true/false,有时候也可以使用计数来进行筛选,这个问题就是一例。
3 N" m2 B2 [6 P. L5 I5 U- u- h    首先,如果问题有解,则解必小于 5 * 7 = 35,只用在此范围内筛选即可。  I% K. V! M. ~, K- Y$ t* m- D, j
    在程序处理上,如果一个数满足一个条件,就将计数值加1,最后计数值为3的即为所求。' N- k' ^* B; P8 |- j3 C4 `
! F9 M) ^8 B( k! x  _; U1 T2 A. F9 O
void fun3()
' X" q" N$ c) m& H. t{
* Z  G$ X5 j. e    int a[105];//105 = 5 * 7
8 q' Y! L4 f8 ]8 t# A    int i;" X" x3 N) ?- N3 g8 i! E5 a2 `
    //计数清0
3 ~6 X/ S+ t- o# Z    for ( i = 0; i < 35; i++ )( z$ O' q) c: o0 \
        a = 0;; }7 D5 Q- Z- Z: Q" F  e
    //开始筛选
5 T4 v% b9 Z6 E$ q3 O4 h  i    for ( i = 3; i < 35; i += 5 )6 [+ g8 ]; ?9 \9 A. G/ z
        a ++;
4 Q6 w; o( q; v8 w# k5 M    for ( i = 2; i < 35; i += 7 )
4 K! _' L' j% O: e4 g0 t        a ++;
7 y) \' y7 Y( k3 \  \4 x, K7 C" Z7 N( c1 i1 Z  \; z/ t
    for ( i = 0; i < 35; i++ )' m+ T5 n" j0 Y) y) F1 w" q' R3 A2 ~
        if ( a == 3 )/ M4 X+ v3 N9 T" a
        {
% O! L6 l  W  T# j" ~( y/ @4 f' [            cout << i << endl;' ^9 h& R, f3 {; x6 C/ G
            return;
4 D% w3 h2 |3 f4 D        }/ m, d) ]5 \; a9 C
    //如果执行到这里说明无解, ]7 x% u7 l1 e8 }
    cout << "No Answer!" << endl;3 k+ H6 [8 W. k1 m- q. m! @
}$ G  |8 x$ X6 q3 r% \2 n' }

) \, @' e& U9 N. \
) @5 z" R2 Y+ w. {3 H5 j: q! @; i总结:
  ]0 K! h; T1 }9 Y& }2 v/ O    筛选法的时间效率较高,但需要一个辅助数组,这就意味着对规模很大的问题不适用。例如第3个问题,条件多1个,需要的空间就翻几倍。解决的办法是:
; c$ f. C; a1 E$ b  F3 g; z
! O# f* ?9 v/ H' ^! t1 R5 Q: x7 bfor ( int i = 0; i< n; i++ )2 F- n  r$ t/ H+ }( O
{
- `- |6 P: I: K6 @    if ( i % 5 == 3 && i % 7 == 2 && ... )4 ~* e1 {9 Q0 q2 b( _6 D# Z
        cout << i;
6 o2 D  p- \: Q}$ h9 E0 K. P9 @1 L, x) ?4 q
    但相应的,这样做速度就慢了下来。所以还得根据问题的规模来决定使用什么方案。" y$ C% c3 V, q* H
) D; h$ b5 K- `, [" x/ [
    总体来讲,对于可以条件判断较复杂,且根据前一个(不)符合条件的情况较简单的推出下一个(不)符合条件的情况,(不)符合条件的情况分布较稀疏的问题,用筛选法速度较快。如果第3题中加一个条件被2除余1,用筛选法就不太合算了。  Y+ `& @4 V0 A6 p; S0 ^

/ \$ l& r% o1 }) F3 h    最后说明一下,此次给出的程序目的在于说明方法,在效率并不是最高的
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, 2026-4-18 16:14 , Processed in 0.301794 second(s), 58 queries .

回顶部