QQ登录

只需要一步,快速开始

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

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

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

7

主题

1

听众

43

积分

升级  40%

该用户从未签到

新人进步奖

跳转到指定楼层
1#
发表于 2004-6-8 16:42 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
所谓筛选法就是从全集中将不合格的项全部删去,剩下的就是答案。
0 e% S6 h- V+ D; v
+ ^- c/ b0 N4 O. A: l/ o1: 求1-100之间的质数
/ U8 a3 i+ Q, Q, P
8 F* l9 t5 e& T0 F) {1 ?& J0 t    原理:先将2的倍数全部划掉,再将3的倍数全部划掉……直到将10的倍数全部划掉(10^2 = 100 )。剩下的就是质数.9 C( u! n/ X# F+ E% H. z
. D. c/ s( z- M( ^8 A; p9 x
void fun1()1 Q3 F* q9 I$ w9 K. `% y0 X
{
- z" E' H& H: [8 g+ S6 p, E    int i, j;& z8 E$ Q4 H, K5 _: B
    bool flag[100];
+ Z; L3 M7 l; _0 u4 F% R) p  z
7 l4 e, m4 K" L2 d+ [: ?: G, q2 p    for ( i = 2; i < 100; i++ ); v& u$ v0 S7 g" p3 p! z: f
        flag = true;
  r2 B1 j4 G2 D0 n1 m2 J1 q) L. O* ~5 V) q- V2 J7 L5 Y3 ?
    //下面开始划掉合数- F, B& S4 D/ \! n$ Q' i
    for ( i = 2; i < 10; i++ ) //因为合数的最小正因数不大于它的平方根! t& F9 H' N5 k. T6 ]; b
    {
2 P; ~7 V$ |. h0 h& Y& e        if ( flag == false )7 q$ Z- G% [# P7 V6 a* x4 J5 B4 F
            continue; //既然i已经是合数,它的倍数应该已经被划掉
% e7 g. M, C) m! K* z; D        for ( j = 2; j * i < 100; j++ )//划掉i*j' e$ g1 L# I/ q9 z
            flag[i*j] = false;: f0 z% D/ c2 b8 m$ R: B
    }
2 y, u5 H* F) ]! g$ E# O  E; \
+ F  E, E" C, _5 O    //输出结果
- k" g" e5 K8 K6 F    for ( i = 2; i < 100; i++ )% M* X; z8 {; x  w& o% c
        if ( flag )8 b( \2 A5 S% q5 o/ ~  e
            cout << i << ' ';9 R4 e+ c' ~# `" \0 {
}# a: G& w+ x$ C
8 E7 `$ W$ m0 F: J
2: 30个人站成一圈,从第一个人开始报数,凡报到5的拉出去毙了,剩下的人接着从1开始报,直到只剩一人放掉。想活命该站哪?
) `4 s/ X' L6 Z) P# W& c6 X' Z( _$ R: Y, c
    这是个经典问题,解法就是模拟整个过程,有点类似于循环队列。
* f' b. p3 B) ^( C- q  h8 L( T7 r: v$ K1 J! X
    另外,为了程序上处理方便,可以假定所有的人都拉去毙了,然后看一下最后一个被毙掉的是谁。另一处为了处理方便而采取的措施是pos的初始值设为-1.很多时候,对问题的问法稍作变动,或者将初始值、加减变量的位置稍作调整,用程序处理起来会方便很多。4 ^/ T& G! W" p" y
# x% T$ A1 S( t( a
void fun2(). s$ X. i1 T5 D6 p; o
{
0 @/ G& V6 T% e- c$ k6 _    bool flag[30];//标记第i个人的状态,false已被毙掉,true还没被毙掉/ Q7 C0 G5 \$ @5 p& x8 k; {

1 B3 j7 d2 ?$ [    for ( int i=0; i< 30; i++ )) d. R3 D5 g4 O- c' f
        flag = true;/ r4 y" s, Q6 e) A+ u, X5 A
% X6 I) Y# {2 H+ n$ Z5 z( I
    int n = 30;//还剩几个人
, y9 P! Z; p( [    int cnt;: U- j# D/ s; C; ~
    int pos = -1;//初始值不一定从0开始,设为-1处理起来较方便4 V% l" }* U/ H- I" J4 ^% e
    while ( n > 0 )
3 M+ g4 k5 t2 |; F- S  O    {8 s4 a3 F# v' U* n
        cnt = 0;9 s" q8 N- d5 I( v5 g$ t' o
        while ( cnt < 5 )5 e$ ~5 o9 I( R8 p! `( R
        {3 {# _' I: |. \( s( z
            if ( ++pos == 30 )/ M. F3 R  n/ [' V/ K- A
                pos = 0;. M% j+ ]; h% S
            if ( flag[pos] )//此人还没被毙掉
2 Q. A- G6 X! O                cnt ++;
) j" y+ Z' ~$ a- k& J! }3 x        }
# B7 X2 H0 g% L/ k/ k        //退出时cnt == 5,pos指向报5的人
9 `4 j+ q3 M* I; |( f        flag[pos] = false;//毙掉
+ i+ f& E  }! `3 z* q) @. B9 r  J        n --;//剩余人数减1
( r) }! t0 K: L/ a    }
% ?3 c& Y1 X. R( _    //最后一个被毙的就是幸存者  i' `, A" L9 N2 W
    //之所以加1是因为程序中从0开始计数,输出却以1开始计数( I+ |- U7 P5 {  I
    cout << pos + 1 << ' ';( S+ S" Y( U4 b( T- S# Z" i  t
}
6 [2 k2 r; v- t! R$ H0 X1 \! U+ u3 p0 G' ^! P2 ^/ Z  d
3: 一个数被5除余3,被7除余2,求此数最小为几。
  J. L8 i8 W$ t( G2 |& ?. B4 K& m
  L' ?- J8 q1 @8 k/ H    筛选法不一定非要标记true/false,有时候也可以使用计数来进行筛选,这个问题就是一例。
( d0 t$ \6 |. R. A. G3 K0 r    首先,如果问题有解,则解必小于 5 * 7 = 35,只用在此范围内筛选即可。
% I7 t8 [% y: W7 J' L    在程序处理上,如果一个数满足一个条件,就将计数值加1,最后计数值为3的即为所求。- Y7 V0 O% ?, Y' t$ Z5 B
- u- h' l) \! t) \$ y
void fun3()) \0 E, Q! O1 S
{; P7 p1 w' [' k2 m2 D8 X4 Q  a
    int a[105];//105 = 5 * 7+ @3 [. J2 r+ p+ i9 S8 n
    int i;2 L: _6 N+ |4 h
    //计数清0
! [% j# ^1 a6 B+ u7 o1 e& a    for ( i = 0; i < 35; i++ )( A+ V9 ?  n& c* G4 E: S9 {. T
        a = 0;
$ _* R4 l2 l8 z+ s+ N8 B, o1 J    //开始筛选% }; k: z" U1 }7 U, X0 Z: @
    for ( i = 3; i < 35; i += 5 )1 g1 o: D0 N$ I, }: ?( _0 O' I7 c8 |
        a ++;
' c3 V% i1 H+ _# A% ]; G    for ( i = 2; i < 35; i += 7 )
8 O9 W( @' h2 B; z# ]+ t        a ++;1 e8 B4 k9 d" M5 f/ H( C1 N
6 B$ t$ Z; S( y5 o2 K8 z
    for ( i = 0; i < 35; i++ )
; H4 P! l$ L+ |0 b* Y2 |        if ( a == 3 )
; S) h2 Y' q' {. {+ ~        {# j" I5 u3 ^2 x
            cout << i << endl;) a# O% X% F2 m5 Y  c! v
            return;
3 S, N: j' L$ T- M% \4 ~5 H1 b        }, U0 g7 x: }8 g  x
    //如果执行到这里说明无解
6 d3 l- u" `. A: @  [" K    cout << "No Answer!" << endl;
; `+ c- D$ b3 ~}
, g, C; r- v2 Q7 V
0 b7 s, Q' t6 G9 A- z% Z4 m* F' M9 T
总结:. x  p# W$ X" @
    筛选法的时间效率较高,但需要一个辅助数组,这就意味着对规模很大的问题不适用。例如第3个问题,条件多1个,需要的空间就翻几倍。解决的办法是:& m1 K- _" z% }

& u/ H! _/ X7 N6 G3 Ofor ( int i = 0; i< n; i++ )( _% d7 r  f9 j+ l, y
{
) `% f8 b9 h# \/ }0 ]    if ( i % 5 == 3 && i % 7 == 2 && ... )
" ?1 Z( e6 }' y9 q        cout << i;; P% Z- v3 l; \* J
}5 J7 e4 M& G8 s/ r+ M4 c
    但相应的,这样做速度就慢了下来。所以还得根据问题的规模来决定使用什么方案。
* R* O  N; _4 `; z* d3 J4 c$ C2 @9 h. v5 A8 O# @) e% r7 J
    总体来讲,对于可以条件判断较复杂,且根据前一个(不)符合条件的情况较简单的推出下一个(不)符合条件的情况,(不)符合条件的情况分布较稀疏的问题,用筛选法速度较快。如果第3题中加一个条件被2除余1,用筛选法就不太合算了。: r( a8 n& ?; v2 Q+ ]- @
- T# L, n: N- E  o9 Q3 C
    最后说明一下,此次给出的程序目的在于说明方法,在效率并不是最高的
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, 2025-8-26 12:37 , Processed in 0.610668 second(s), 52 queries .

回顶部