QQ登录

只需要一步,快速开始

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

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

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

7

主题

1

听众

43

积分

升级  40%

该用户从未签到

新人进步奖

跳转到指定楼层
1#
发表于 2004-6-8 16:42 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
所谓筛选法就是从全集中将不合格的项全部删去,剩下的就是答案。- ~  t: M2 I+ s; N" F
- x% @& D, x, U7 m
1: 求1-100之间的质数5 }# `. ?6 q$ j; j7 r
4 _- S) G* ]) j. E+ D
    原理:先将2的倍数全部划掉,再将3的倍数全部划掉……直到将10的倍数全部划掉(10^2 = 100 )。剩下的就是质数.: n3 {. r" q' S' C' V2 _+ E. {5 q1 L$ i

. Y' k8 ~: q3 n2 z6 ivoid fun1()
! o- p1 _" b" l  S5 t{1 o% d1 J. ~7 {
    int i, j;
. g2 h4 l& `$ n; ~7 v2 Y5 H6 W1 w9 p    bool flag[100];! I6 s" g4 d$ L; K

1 p; r3 C* ^& f3 M1 c5 C7 l    for ( i = 2; i < 100; i++ )5 V1 y. B! D) }3 _$ c& j  A) H
        flag = true;: M1 j/ K  {1 O4 d) s  b. b

6 V- D: k) O( N. f    //下面开始划掉合数4 O1 k7 W: z) a2 J4 n4 _
    for ( i = 2; i < 10; i++ ) //因为合数的最小正因数不大于它的平方根. m% g+ L2 ]0 p( I
    {
4 B# x) R$ c7 q/ X. E1 T# C        if ( flag == false )9 q1 s( ~( a! K3 C' o. C' x7 B
            continue; //既然i已经是合数,它的倍数应该已经被划掉9 {6 t4 j4 H! K& P3 O) n
        for ( j = 2; j * i < 100; j++ )//划掉i*j
+ R3 ~" |8 W) F* Y9 I            flag[i*j] = false;
' x5 B+ p# t- C/ t8 n# J0 M    }
) f' ^1 E6 c: U" k# ~- r6 r% |) w+ d+ X% Y7 ]+ o* K
    //输出结果1 D  o( K% b0 }8 M# L& t6 n2 p
    for ( i = 2; i < 100; i++ )
. ^3 O; h  O' l3 N' M        if ( flag )
; i) m- i' T6 y) B            cout << i << ' ';; n: m6 J  s" R) o
}3 ?& G3 @/ U! s. t; P+ c
- o* k3 b  w/ u& ?& O* d2 G
2: 30个人站成一圈,从第一个人开始报数,凡报到5的拉出去毙了,剩下的人接着从1开始报,直到只剩一人放掉。想活命该站哪?8 V! v. M( B5 L# O

6 `- a1 g% ~& s+ X$ z    这是个经典问题,解法就是模拟整个过程,有点类似于循环队列。
& y/ f$ G$ z& f2 s: W/ Q0 @
" G0 v+ |4 x6 R4 C9 y+ f! E    另外,为了程序上处理方便,可以假定所有的人都拉去毙了,然后看一下最后一个被毙掉的是谁。另一处为了处理方便而采取的措施是pos的初始值设为-1.很多时候,对问题的问法稍作变动,或者将初始值、加减变量的位置稍作调整,用程序处理起来会方便很多。
' F6 i- n4 I& d# P/ K: n
' D7 t, x- _$ {0 z$ B* e! \3 Ovoid fun2()7 _$ S- R2 N* \; c1 g
{( h: n3 [) n  W5 L4 e3 g, w0 w
    bool flag[30];//标记第i个人的状态,false已被毙掉,true还没被毙掉
3 x& a0 i: n# p2 R7 ^( P* y
7 z( Z9 @" Y9 O# B" |: X; {; b    for ( int i=0; i< 30; i++ )0 K2 F; K! I* k  G: {3 @* d
        flag = true;
) Z# z5 j9 M, @% c% c8 p$ v" d$ s( S" {' h. {( l0 _5 d
    int n = 30;//还剩几个人
9 @4 G: p! C0 K/ |' t# W    int cnt;
2 O) B3 \% P1 X+ f# k- M. b    int pos = -1;//初始值不一定从0开始,设为-1处理起来较方便
( I4 _, m6 Q# F    while ( n > 0 )7 S3 K4 i7 x9 U) p6 ^
    {& F0 u1 O$ H; H# l1 g9 \* f: e/ ~
        cnt = 0;
/ P$ P' D( u! L% ?        while ( cnt < 5 )
4 D- }: f  X9 ]$ T1 `; Y        {
; @- x; k- n" w, P) f' c$ v( Q            if ( ++pos == 30 )
3 ~) t* W+ _( B/ j- F                pos = 0;2 @4 ]  E1 l# {' _7 }* O2 w5 w' ?
            if ( flag[pos] )//此人还没被毙掉
" i# p+ Q" C" m: N, Y/ R; H6 Z0 l                cnt ++;
; }/ K3 N' s  C1 f0 M! }        }
2 A2 j) |) K! y! S. {        //退出时cnt == 5,pos指向报5的人4 ?* V9 `# \, D8 x/ ~3 O
        flag[pos] = false;//毙掉& N+ @. B6 P: p4 y  j( \2 n# y1 o$ O+ l
        n --;//剩余人数减1
" P4 `# X" @- k7 [- |    }7 F0 \/ E9 F$ C, ]
    //最后一个被毙的就是幸存者
, h! Y$ L: Z5 q    //之所以加1是因为程序中从0开始计数,输出却以1开始计数7 @; P' k  c. E$ E0 |
    cout << pos + 1 << ' ';
4 D5 R3 E7 ]+ T& d- x4 ?}" H$ U! h" y( C! w
  {+ `& h. i) _  y) S5 p
3: 一个数被5除余3,被7除余2,求此数最小为几。
% h7 j9 y2 P8 D/ R
2 Z1 _1 [% c+ q7 ~/ H! Z    筛选法不一定非要标记true/false,有时候也可以使用计数来进行筛选,这个问题就是一例。8 S7 f3 b- ?5 w0 X( }
    首先,如果问题有解,则解必小于 5 * 7 = 35,只用在此范围内筛选即可。" g% G9 s8 O- s
    在程序处理上,如果一个数满足一个条件,就将计数值加1,最后计数值为3的即为所求。# F. K- h; o* C; E( z

6 Y2 n" h  b: n! Dvoid fun3()+ k1 c# \1 D4 @: t( l. g, a
{
8 f+ p- d& T6 t2 D    int a[105];//105 = 5 * 79 w% e* X; ^$ o5 ~4 D
    int i;
) u% x4 M5 O, a# n8 O    //计数清0
0 K) Y: E0 _! m/ {5 z) z, }    for ( i = 0; i < 35; i++ )
" a& v2 j4 N, a6 }, _# e        a = 0;
* l+ ]. f: V* ^3 q    //开始筛选+ r: \7 K( J8 u1 P
    for ( i = 3; i < 35; i += 5 )
# `; J  W8 J& n" f        a ++;
1 o( Q# z! ?. b* B' l    for ( i = 2; i < 35; i += 7 )
/ j% u% I7 k! M7 F/ M0 L! _        a ++;% P9 [3 Q/ b; b9 ~# c& J% l

- q) d! H: ?9 l/ u& J/ U) j    for ( i = 0; i < 35; i++ )- u% X% A2 W# H4 J# b% `
        if ( a == 3 )3 x) l1 U/ g1 Q4 L5 E8 G
        {
- _7 ~2 T9 g8 ^            cout << i << endl;
% X9 [# S  f3 V& G            return;- p) c' o1 n% g# ^" X" D0 Q
        }
7 k+ K7 l' F0 }6 `: Z    //如果执行到这里说明无解& S% g# Z: m- _1 V6 F  ~
    cout << "No Answer!" << endl;. A9 R+ h, r( A2 V
}) t4 |7 R* ^1 _9 j+ A$ ^$ Q
7 c  d; R+ g& V! x! y- V( q( j

; N- q1 o8 J% a# I总结:0 i. E( ?3 X3 L
    筛选法的时间效率较高,但需要一个辅助数组,这就意味着对规模很大的问题不适用。例如第3个问题,条件多1个,需要的空间就翻几倍。解决的办法是:
4 C5 e% r4 D8 n. s+ D) X
6 b7 x& P. y7 k4 I4 {for ( int i = 0; i< n; i++ )
6 V- |) J- {. o  z. J* A{
) p/ B' A. ?: o& E3 f% e    if ( i % 5 == 3 && i % 7 == 2 && ... ): J, |8 k, A, `9 ]3 n
        cout << i;
- s3 @4 z$ I' n/ v, f2 Q0 U  Z}
. a8 y. D  J  w9 q8 z    但相应的,这样做速度就慢了下来。所以还得根据问题的规模来决定使用什么方案。  i. @/ J5 S9 G; q  ?7 v- C( b

$ ?5 C  _; _3 H2 s) [4 g* V7 n0 p$ w    总体来讲,对于可以条件判断较复杂,且根据前一个(不)符合条件的情况较简单的推出下一个(不)符合条件的情况,(不)符合条件的情况分布较稀疏的问题,用筛选法速度较快。如果第3题中加一个条件被2除余1,用筛选法就不太合算了。
( `- N7 o! O, K0 }- N8 \4 T, m
( I8 _! _* |& O4 n" I! \0 j    最后说明一下,此次给出的程序目的在于说明方法,在效率并不是最高的
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-19 01:24 , Processed in 0.430253 second(s), 57 queries .

回顶部