QQ登录

只需要一步,快速开始

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

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

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

7

主题

1

听众

43

积分

升级  40%

该用户从未签到

新人进步奖

跳转到指定楼层
1#
发表于 2004-6-8 16:42 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
所谓筛选法就是从全集中将不合格的项全部删去,剩下的就是答案。
$ q& W- C2 r, }, V; n6 n" ]- n
6 ], F4 G% Z8 f1: 求1-100之间的质数
, D% V: g# n4 g, H6 `! l8 ^+ U8 Q+ ]: q3 L: C* @
    原理:先将2的倍数全部划掉,再将3的倍数全部划掉……直到将10的倍数全部划掉(10^2 = 100 )。剩下的就是质数.& n+ p- K, w; x: V0 W
) ^2 u7 F1 D$ E7 D0 n; u
void fun1()/ P1 x. F0 F2 X' M
{% D( O$ X+ h5 L& W
    int i, j;: k) v/ r4 g3 T0 i" i; q# S* B9 r
    bool flag[100];) L9 ]$ X6 g: U. f

- o3 P! N* [' b! X) P    for ( i = 2; i < 100; i++ )% ?9 b9 J3 D7 R1 ^9 }( g  |
        flag = true;
+ |, K; g8 }3 @$ v0 _: W' J$ f
, Q4 t8 g4 ?9 G0 |6 c4 ]    //下面开始划掉合数  z$ P: f( \8 Y( h+ k+ i
    for ( i = 2; i < 10; i++ ) //因为合数的最小正因数不大于它的平方根; ?7 Q3 N1 X& V* J
    {
" a: V: j8 |( {7 r        if ( flag == false )
; O6 S9 E2 r5 V! B            continue; //既然i已经是合数,它的倍数应该已经被划掉
( y" M- Z4 t; ^: P- A        for ( j = 2; j * i < 100; j++ )//划掉i*j- y1 h" d& q  ^; _
            flag[i*j] = false;
' {9 l  X3 X/ c9 q    }( q4 l; n) z2 Y$ l. B) E& c; z
( d0 v; x; \. m$ t9 J+ A$ S
    //输出结果1 V" O, A) C3 y4 {7 q5 N
    for ( i = 2; i < 100; i++ )* o/ z3 G6 M6 L
        if ( flag )
3 X9 h" L/ B8 o, g6 ~4 O, B            cout << i << ' ';0 o8 b- E2 t6 t; j
}- m9 N  V7 M8 `

- i, L# E- s* C2: 30个人站成一圈,从第一个人开始报数,凡报到5的拉出去毙了,剩下的人接着从1开始报,直到只剩一人放掉。想活命该站哪?
/ v/ `7 T5 Z& Q' n8 S2 n% K0 u, i& ]' ~) H# O% D6 k* F6 q: e
    这是个经典问题,解法就是模拟整个过程,有点类似于循环队列。- `6 x1 X& k+ ^- s7 b

3 l, t6 N3 G; {1 @* T    另外,为了程序上处理方便,可以假定所有的人都拉去毙了,然后看一下最后一个被毙掉的是谁。另一处为了处理方便而采取的措施是pos的初始值设为-1.很多时候,对问题的问法稍作变动,或者将初始值、加减变量的位置稍作调整,用程序处理起来会方便很多。
$ f6 \/ Q. ^4 W; R( {+ [' l: U, @0 A/ S+ A  a& y$ v' l9 l
void fun2()6 c5 ?% T2 y' i& V$ P3 H0 S0 z' P
{6 X, ~- q/ b) b8 G. T0 T: y
    bool flag[30];//标记第i个人的状态,false已被毙掉,true还没被毙掉
  z0 I. }7 N% l; Z; i
) Z, M" x) |/ E& w4 |8 |# ^* \    for ( int i=0; i< 30; i++ )) W2 U, a* G0 ]9 U8 z4 U# g# S3 `
        flag = true;+ l% T# G3 T# u3 Q4 y
; o8 d) |& i/ C4 _( A* s
    int n = 30;//还剩几个人
+ n$ S4 g( B2 [9 E$ C( T+ F- h8 r    int cnt;
+ T: z2 t' \8 u5 S. m    int pos = -1;//初始值不一定从0开始,设为-1处理起来较方便7 K9 n, u8 R, _- l; e
    while ( n > 0 )
2 P2 y! w; d1 Y6 c8 s    {+ p! M- F: P1 F  k0 \( S
        cnt = 0;% Q, D3 b* q% d' C1 m" V
        while ( cnt < 5 )
' p: e- |% @: d; v' Y# p        {
7 I! N$ J$ c* W" [" l            if ( ++pos == 30 )( x, _  o/ o/ I8 s4 z+ K+ i
                pos = 0;! l  J! j( I! ?: g
            if ( flag[pos] )//此人还没被毙掉% b/ s- B& z2 Y6 E
                cnt ++;9 P& W6 h8 R7 l3 I, T% r  Y
        }
) r6 X3 v5 ]/ y' v9 N6 B        //退出时cnt == 5,pos指向报5的人
1 J/ S# f8 U8 g2 \        flag[pos] = false;//毙掉9 q. d. c* y7 j1 |
        n --;//剩余人数减10 d$ O) J, U; c. R  e) A
    }
( y5 N0 _( x8 ^    //最后一个被毙的就是幸存者2 o1 y( z9 J; A1 G
    //之所以加1是因为程序中从0开始计数,输出却以1开始计数% u0 K' @+ X. T  t5 {
    cout << pos + 1 << ' ';0 Q/ V' g. b/ b
}1 x8 e' d+ q: L9 o
( T- A. \; g' u. g9 f
3: 一个数被5除余3,被7除余2,求此数最小为几。+ \" o5 v$ {, i' d+ t

2 Z- L- T& H0 A' C; B/ |; a    筛选法不一定非要标记true/false,有时候也可以使用计数来进行筛选,这个问题就是一例。
* m1 E& p! T3 j2 o9 d% J, _    首先,如果问题有解,则解必小于 5 * 7 = 35,只用在此范围内筛选即可。6 c9 E9 V/ s+ V9 g5 D! ~5 W
    在程序处理上,如果一个数满足一个条件,就将计数值加1,最后计数值为3的即为所求。& O9 H8 L8 o! g+ r1 r( `
. H6 e4 C* O( k  P) \5 B; ^
void fun3()
- k7 i9 I9 }7 p0 Q# x% W5 X1 u{
6 I& W8 |3 u. Z% @0 d    int a[105];//105 = 5 * 7' |6 F7 P& n0 N' y: d: V" k
    int i;
  W9 S# I0 A) O% W+ g    //计数清0
" T1 w1 P, {, s  C+ ]: K    for ( i = 0; i < 35; i++ ), y8 D8 B' `$ @$ t% U2 B$ d3 v8 b* a
        a = 0;) }" T0 v0 n# o# q( p  L1 M
    //开始筛选
5 k5 E$ t5 K; S7 M) L8 Q4 ^    for ( i = 3; i < 35; i += 5 )5 R+ _* F* j- Z  k+ z( z& A
        a ++;& E5 A. J3 L" d$ y
    for ( i = 2; i < 35; i += 7 )
0 w3 m; Y9 J, c  w- S1 v        a ++;
6 t" n1 z9 _( k( |, D& ?- B, F5 r4 |# B0 W* @- Y
    for ( i = 0; i < 35; i++ )1 ~8 V% Z7 c& ]9 ]% r5 q3 [& w
        if ( a == 3 )
% B+ L0 b7 w! y* K+ I        {
6 L- j2 M' c% E: j0 X            cout << i << endl;1 o1 J; s7 b4 d2 v: P  y  l+ V2 F- P
            return;
& N2 e0 P, y( K" j7 O        }6 u/ ^8 j* M$ i* d
    //如果执行到这里说明无解2 [% J; U; _* n. B7 e& B
    cout << "No Answer!" << endl;
/ r3 x- R3 ^# J0 J}& t  C& T3 O$ n
7 J  p" x% D  n, N3 H  v. Q
* n8 @; a" T, J1 ^& S+ J4 |' ?
总结:* h7 R# c. k, v+ }/ ?
    筛选法的时间效率较高,但需要一个辅助数组,这就意味着对规模很大的问题不适用。例如第3个问题,条件多1个,需要的空间就翻几倍。解决的办法是:
3 B, C3 f3 Q( X! X/ F( J
; h' R5 ~6 g5 i& Z1 Yfor ( int i = 0; i< n; i++ )
& I6 \- G4 a# O/ E& _- D0 Q{
5 g- s, \/ D" j: E    if ( i % 5 == 3 && i % 7 == 2 && ... )* g0 g& a8 c  S( D5 h; K
        cout << i;5 G  g  n) C& a' P  N
}
) S) w5 g: T+ Z+ r1 I    但相应的,这样做速度就慢了下来。所以还得根据问题的规模来决定使用什么方案。
$ F, Y. a% g5 I0 x: S1 \# L1 R9 @  b2 }( q
    总体来讲,对于可以条件判断较复杂,且根据前一个(不)符合条件的情况较简单的推出下一个(不)符合条件的情况,(不)符合条件的情况分布较稀疏的问题,用筛选法速度较快。如果第3题中加一个条件被2除余1,用筛选法就不太合算了。# t8 w# I4 Q4 f
6 Z  Q, s( v5 Y8 d, Y4 X9 b# 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, 2026-9-2 01:44 , Processed in 0.332020 second(s), 58 queries .

回顶部