QQ登录

只需要一步,快速开始

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

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

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

7

主题

1

听众

43

积分

升级  40%

该用户从未签到

新人进步奖

跳转到指定楼层
1#
发表于 2004-6-8 16:42 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
所谓筛选法就是从全集中将不合格的项全部删去,剩下的就是答案。
; e8 m5 U3 g  r; l1 g
7 B/ h$ _) f$ m/ M" g4 l1: 求1-100之间的质数
4 V: x  P- x5 z3 \' ~! G
1 ^6 X; X8 I6 Y6 k    原理:先将2的倍数全部划掉,再将3的倍数全部划掉……直到将10的倍数全部划掉(10^2 = 100 )。剩下的就是质数.
: D4 l7 A* K% `5 W3 @/ {: L* v7 H  X: Z( a- o( r
void fun1()
- e( V6 A( Y  v0 p# U4 g( y: `{: }! a* E: Q4 c
    int i, j;$ P, X+ n+ w1 C% w8 X" z
    bool flag[100];& b+ v" |, P' T# \' [; K3 H* C
% g5 M. ?. W# f& y1 S$ q
    for ( i = 2; i < 100; i++ )
1 s/ O9 w; w  a: n$ Z* p6 l/ c" q        flag = true;9 w: R) P) o( Z& o- c
3 F- I0 C6 Z9 M* S: k* K
    //下面开始划掉合数
3 i6 j- ^6 m  ]  X& E7 @/ x    for ( i = 2; i < 10; i++ ) //因为合数的最小正因数不大于它的平方根1 v% j1 g, u% s3 X4 F2 ~- a9 A
    {! }! ?% v* ^6 O* |
        if ( flag == false )6 n* d) n) z* a# s7 N( W
            continue; //既然i已经是合数,它的倍数应该已经被划掉
2 J2 V; X4 H7 I9 F" R& _! D+ R        for ( j = 2; j * i < 100; j++ )//划掉i*j
. w) b6 v5 [6 K; d! Z            flag[i*j] = false;: C4 W* L: v# e/ K8 v8 @5 I, H
    }
- d% ~6 C# s/ V- ]
$ i$ a8 A2 H* x) F2 F! c    //输出结果) M' T7 M# A  r, @" ~! U- S3 }
    for ( i = 2; i < 100; i++ )( \/ @1 C$ c: R0 R" _5 K% ^4 P
        if ( flag )
# L  i) {4 X+ C) Z% W; s' g            cout << i << ' ';0 ?5 e3 Z* c' Z: I5 T
}
! u! }2 M, }6 g
: h3 s+ A0 K* `! O( A1 v' V2: 30个人站成一圈,从第一个人开始报数,凡报到5的拉出去毙了,剩下的人接着从1开始报,直到只剩一人放掉。想活命该站哪?. I6 }; ^6 g. E$ s6 C
# c" V; p. v2 W% D0 a( p0 u7 A, \
    这是个经典问题,解法就是模拟整个过程,有点类似于循环队列。, H! B, T/ s, U  i" |1 A1 F6 e
0 ]8 V# f" m7 x5 ?! _8 Q  W& B: o
    另外,为了程序上处理方便,可以假定所有的人都拉去毙了,然后看一下最后一个被毙掉的是谁。另一处为了处理方便而采取的措施是pos的初始值设为-1.很多时候,对问题的问法稍作变动,或者将初始值、加减变量的位置稍作调整,用程序处理起来会方便很多。3 F2 n4 ^6 Z/ E" Q) |6 {+ C

5 f1 h- {, K& V4 O- Rvoid fun2()) l% e( g& S. @
{
; R& s0 m2 e: _; Z( B8 E; Z    bool flag[30];//标记第i个人的状态,false已被毙掉,true还没被毙掉4 {6 u4 ]+ s' k9 _& s1 Q8 {/ A( L# u" g

+ p$ }3 G7 i" {    for ( int i=0; i< 30; i++ )
, Y5 F' H8 C* ]* ^! b2 n0 Z        flag = true;
8 }+ n+ E& b6 J4 w% H" w5 e& r
& m+ ~8 w+ m+ p, @    int n = 30;//还剩几个人
% U# m& J1 n$ g& C; h    int cnt;
! d1 B/ v+ V  U* G" C5 g8 Q. j    int pos = -1;//初始值不一定从0开始,设为-1处理起来较方便* _3 R. M+ l4 T( u; o  _& G) k
    while ( n > 0 )
8 o& f6 E0 H( ^5 b    {, I; r- u+ w0 N/ C! t
        cnt = 0;+ F6 Z& n& E- I+ \5 W8 i
        while ( cnt < 5 )
: T, v9 S  C3 n        {
6 v6 j4 R0 D$ D( E0 d1 w            if ( ++pos == 30 )5 H# {; X, e/ B4 z: h; B5 P
                pos = 0;( o* Z% L8 u# y+ }
            if ( flag[pos] )//此人还没被毙掉, V$ m' a( D/ G0 }$ _8 j# J0 Q
                cnt ++;3 M& G, t. n  R- b' L5 W
        }  ?. k; m" K9 b0 u
        //退出时cnt == 5,pos指向报5的人
/ K, j( _0 O! r; j/ F7 l        flag[pos] = false;//毙掉5 |+ T" Y0 D: J; O. T% d
        n --;//剩余人数减1
( d3 n' F1 b+ a6 X# B    }
! [0 k, h5 z' z% j8 S) S4 \    //最后一个被毙的就是幸存者5 I6 m; j. S% G6 S" @& E
    //之所以加1是因为程序中从0开始计数,输出却以1开始计数
/ q: z; w5 d8 H2 D' S* x) O    cout << pos + 1 << ' ';$ X* h0 X6 g3 ~9 x
}; f5 }; R/ c# y
3 U4 M8 y7 R% J  m3 W
3: 一个数被5除余3,被7除余2,求此数最小为几。
" \+ C& W8 T2 z- K# @3 ~5 |2 K! j2 k! b. Z: }6 Q( M
    筛选法不一定非要标记true/false,有时候也可以使用计数来进行筛选,这个问题就是一例。$ a5 y- ]( s6 I& {( c! y
    首先,如果问题有解,则解必小于 5 * 7 = 35,只用在此范围内筛选即可。# `4 A) l: _" \  {8 C. y
    在程序处理上,如果一个数满足一个条件,就将计数值加1,最后计数值为3的即为所求。
6 K1 M* ]! [3 R- D; x9 S- ?* o8 T3 P+ {9 j
void fun3()
! o: Z6 o- n1 Z{* D7 O- r% a9 p1 A  I
    int a[105];//105 = 5 * 7
# {8 Z5 B& M# d) {5 s    int i;( w9 s# x+ h: X, B& M
    //计数清0' e- n  S1 _9 k/ O
    for ( i = 0; i < 35; i++ )
; b' O6 I3 ^5 M  [* A6 ^        a = 0;0 j# L4 U) ]% c, |3 A8 S; k* g
    //开始筛选
, \5 E0 {% `+ C: m; d' B7 h$ ]    for ( i = 3; i < 35; i += 5 )
! G- h& T* J* N2 i9 C        a ++;
& S" ^) ~, I% i/ z' N- p# {0 ~; t    for ( i = 2; i < 35; i += 7 )* _0 D) x$ Z& {, l. S
        a ++;7 \( W% |+ `/ ]) }8 L- L' e

( R6 @$ d! R; ?8 _" \9 z) b9 \& c; i    for ( i = 0; i < 35; i++ )
, b% I! r4 l) l5 {        if ( a == 3 )' i% p9 S0 O5 n' ?' K  P
        {- w, N( F6 j9 |# O
            cout << i << endl;+ j* p% W' C" j: Y) G$ F) q
            return;
+ e  _! R3 V$ |+ l  M, |        }- G1 u& o! Z' [2 a) [" C
    //如果执行到这里说明无解
; o3 a6 f, O" y2 W4 Q* J    cout << "No Answer!" << endl;
. l5 \& p( R# B$ q}
4 t# q! W1 h. a$ t" m+ A7 Z# x
; z/ s9 n* ]# Z% Q' N2 a7 v+ `# t& `
总结:
0 Q7 Y$ g6 t. w+ t5 x, j/ G    筛选法的时间效率较高,但需要一个辅助数组,这就意味着对规模很大的问题不适用。例如第3个问题,条件多1个,需要的空间就翻几倍。解决的办法是:: j) n/ ?; T+ s) {# T
1 ~  p$ }% f4 Y9 }8 B& U$ b
for ( int i = 0; i< n; i++ )9 q! }1 ]! F! x& J
{  K. \0 s( T1 I
    if ( i % 5 == 3 && i % 7 == 2 && ... )' v) h# f( j/ W/ f
        cout << i;5 }1 C7 N8 R1 l" k9 \0 K& l3 O
}
6 ^$ c) W( M) }5 a6 x1 ~    但相应的,这样做速度就慢了下来。所以还得根据问题的规模来决定使用什么方案。" T; b- N: x" {6 L( l: V1 L( }$ I
, N$ A$ n3 Y1 B$ {' s) B9 g" t( Y) [) q
    总体来讲,对于可以条件判断较复杂,且根据前一个(不)符合条件的情况较简单的推出下一个(不)符合条件的情况,(不)符合条件的情况分布较稀疏的问题,用筛选法速度较快。如果第3题中加一个条件被2除余1,用筛选法就不太合算了。
/ l/ W' h+ |, ]+ R7 Y/ C
- h9 U4 B$ E) Z3 l    最后说明一下,此次给出的程序目的在于说明方法,在效率并不是最高的
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-6-11 16:45 , Processed in 0.327734 second(s), 58 queries .

回顶部