QQ登录

只需要一步,快速开始

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

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

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

7

主题

1

听众

43

积分

升级  40%

该用户从未签到

新人进步奖

跳转到指定楼层
1#
发表于 2004-6-8 16:42 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
所谓筛选法就是从全集中将不合格的项全部删去,剩下的就是答案。
( p! C5 H1 Z/ c1 ]. |/ d" C5 b- m
6 F) U$ H/ F2 ~( P* K0 R1: 求1-100之间的质数
4 @/ n% V7 s# p. J) `, a$ |9 h4 `7 S5 g2 l! l
    原理:先将2的倍数全部划掉,再将3的倍数全部划掉……直到将10的倍数全部划掉(10^2 = 100 )。剩下的就是质数.
5 a, @! O. r' T
4 Y# j; e% `4 b$ i% _  m% n) v" T. Ivoid fun1()' P6 f2 i+ D( X4 s" K
{
  X( D6 Q: u  o    int i, j;
" z/ Y4 w2 L* b. L    bool flag[100];( T2 ^5 \6 e- h4 x

+ W8 O' n+ T) \2 G7 x4 p    for ( i = 2; i < 100; i++ )  \9 \4 K1 F- O! `; |9 W# J. C) ]3 F
        flag = true;0 m5 w+ H' m2 p; B  k# {
' a; n4 }8 \5 @
    //下面开始划掉合数, i* Z, z$ H* ~& V8 U- h# m
    for ( i = 2; i < 10; i++ ) //因为合数的最小正因数不大于它的平方根, q- N  E  J8 G  M
    {+ J0 u  G/ y; u- w$ O! E
        if ( flag == false )) @8 w2 d! d! i; u" Q
            continue; //既然i已经是合数,它的倍数应该已经被划掉) o; o9 V% |5 z, b' c1 w  L
        for ( j = 2; j * i < 100; j++ )//划掉i*j( k7 p; z0 F  P% y8 M! H
            flag[i*j] = false;
* Q* K9 D+ K' v" V% n$ E( N8 W9 G    }
; E; V: Q; n1 [2 r( _  Q- m$ Z; S- u6 J# E- E8 u6 T) ?2 M
    //输出结果
5 K& x* b) d1 B- m' \    for ( i = 2; i < 100; i++ )
7 P$ e9 ]; T6 |3 J        if ( flag )8 c2 @% `2 d% Y8 d. d9 T
            cout << i << ' ';4 {/ n3 d' ~- U" _
}4 ?1 R8 e( t! N; t* e

% X& i+ l* L; J8 P5 ^2: 30个人站成一圈,从第一个人开始报数,凡报到5的拉出去毙了,剩下的人接着从1开始报,直到只剩一人放掉。想活命该站哪?
7 D/ s/ y" Z# U; S/ O+ d( W2 d
2 a  P( U8 L: n2 l5 R; |8 b# p5 {    这是个经典问题,解法就是模拟整个过程,有点类似于循环队列。$ ^7 r: y7 i" @/ F' \; X$ \
0 `' ]9 l6 S, @" e
    另外,为了程序上处理方便,可以假定所有的人都拉去毙了,然后看一下最后一个被毙掉的是谁。另一处为了处理方便而采取的措施是pos的初始值设为-1.很多时候,对问题的问法稍作变动,或者将初始值、加减变量的位置稍作调整,用程序处理起来会方便很多。# Y" b+ `! k1 Z+ }# s  Z9 U
/ z" H+ N8 {! x& [
void fun2()3 f6 ^1 M- z! [& p
{' ]8 L/ `- g/ a* D# G/ O
    bool flag[30];//标记第i个人的状态,false已被毙掉,true还没被毙掉
2 D& @# q6 S$ d) m4 j7 p' t9 ?" J! c, P* I3 S/ e
    for ( int i=0; i< 30; i++ )- S$ L7 m( O5 J
        flag = true;
* u6 w$ w; V& y6 g- K* S7 M2 K1 y) T0 k' O
    int n = 30;//还剩几个人
0 i* D" S% T: k# ]% @7 E    int cnt;: H. {" E% K& y# V) H- Y
    int pos = -1;//初始值不一定从0开始,设为-1处理起来较方便8 o7 y5 D& ]5 k" W
    while ( n > 0 )
% |& r, l3 h& Z2 W' L- J    {
  A+ n! Y5 t8 D% _        cnt = 0;% \  i% I# D1 [& q8 T+ }
        while ( cnt < 5 )7 P# ]7 @& |. b; t7 a2 q
        {  B  X$ S& V& e9 t
            if ( ++pos == 30 )3 z# R; L6 {  r9 s9 Q
                pos = 0;
- W0 t5 G  l( l5 N( F0 L            if ( flag[pos] )//此人还没被毙掉0 a  r8 t4 u! f
                cnt ++;
. I. w: k% b2 f) X        }8 L$ _4 e. h+ O" ?! ?
        //退出时cnt == 5,pos指向报5的人$ [; v7 M! z1 j4 |) i
        flag[pos] = false;//毙掉% x2 T3 w6 Z# t/ Y5 g
        n --;//剩余人数减15 P( ~/ a& B7 M/ G& |
    }
% i0 `1 u0 B/ A0 r( C- c$ _    //最后一个被毙的就是幸存者
3 p$ N8 s5 q# c- P4 j! G. T& L    //之所以加1是因为程序中从0开始计数,输出却以1开始计数
( r+ D6 d' O; P, ^! ~8 Q    cout << pos + 1 << ' ';- E; N- g; e/ L2 _6 f! s2 }1 U. Z8 u
}. ?1 A+ p) g# o( `' l' U5 c

. c, X% p! E+ F9 X3: 一个数被5除余3,被7除余2,求此数最小为几。
+ T5 G* {$ J) S+ J" U0 j# z& X" |' |
    筛选法不一定非要标记true/false,有时候也可以使用计数来进行筛选,这个问题就是一例。
" l4 j4 J- o1 |    首先,如果问题有解,则解必小于 5 * 7 = 35,只用在此范围内筛选即可。4 d2 v; Z& B# ?8 e) A
    在程序处理上,如果一个数满足一个条件,就将计数值加1,最后计数值为3的即为所求。7 Z( e  b6 A2 K" d

8 X( n. s) I/ F; E3 Xvoid fun3()
  R7 o; c* L+ e1 x3 ~& ^% w{! \. ]! o+ i$ ]2 `$ @
    int a[105];//105 = 5 * 7
8 ^: X# l6 z6 i- N    int i;. h* O  G" c$ D, q6 H! }' z
    //计数清0
( U1 y: k! Y3 {+ e' D& z    for ( i = 0; i < 35; i++ ): \# _$ b4 U/ w5 Q
        a = 0;
5 y! X' P. g$ |9 N    //开始筛选
9 ~0 ^2 z; H( q& B    for ( i = 3; i < 35; i += 5 )
5 t0 O& A+ r+ F        a ++;! Q- Q/ ~& j! @  }; ?# M, b
    for ( i = 2; i < 35; i += 7 )8 K$ g! B, \* F
        a ++;, ^' E4 F8 ~' X8 j) K
' a3 j! A5 U* ~$ y
    for ( i = 0; i < 35; i++ ), Q1 F6 d9 ~4 W2 h% h! q* J0 x( N$ p
        if ( a == 3 )
1 e3 [+ v0 _4 o8 @/ p        {
# u; w6 z. V- h% {- E4 z" h$ V            cout << i << endl;
& G# y, d: C( R& p6 i( i: B1 A1 b            return;
4 z% \7 U. L. q        }
3 k9 ]/ j  o8 A9 H    //如果执行到这里说明无解# [6 u7 n' a5 e, K7 j: d
    cout << "No Answer!" << endl;
. j& T8 i- `) d7 F+ w' I. a+ l}
  u* k# T, B# u! H! v, D, S* t* O3 D- }! `# J) V6 |6 L7 O

0 `2 w7 `' @- _; p# D9 n总结:
6 |; L" C' Z" o# H4 j    筛选法的时间效率较高,但需要一个辅助数组,这就意味着对规模很大的问题不适用。例如第3个问题,条件多1个,需要的空间就翻几倍。解决的办法是:- ?# Q) i6 q$ I
. Q' n4 s  n/ s  y1 Z7 ^
for ( int i = 0; i< n; i++ )- b+ i8 l) o" ^5 ^6 f
{
7 D  i7 b, S5 u# W0 s/ A. J+ o$ F    if ( i % 5 == 3 && i % 7 == 2 && ... )0 e4 ^" u" }3 }' G2 v
        cout << i;
: G+ r+ j/ w( k; w4 a}* M8 k5 W6 _0 o8 n: R
    但相应的,这样做速度就慢了下来。所以还得根据问题的规模来决定使用什么方案。
4 {; r: ]* b& O% Q& n7 a9 |4 }5 K$ u- N& E* R/ Q. w
    总体来讲,对于可以条件判断较复杂,且根据前一个(不)符合条件的情况较简单的推出下一个(不)符合条件的情况,(不)符合条件的情况分布较稀疏的问题,用筛选法速度较快。如果第3题中加一个条件被2除余1,用筛选法就不太合算了。$ U, i' N- n# r- r+ H+ {

1 W8 U* E8 R5 M4 ~# 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-9-3 01:26 , Processed in 0.307343 second(s), 58 queries .

回顶部