QQ登录

只需要一步,快速开始

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

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

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

7

主题

1

听众

43

积分

升级  40%

该用户从未签到

新人进步奖

跳转到指定楼层
1#
发表于 2004-6-8 16:42 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
所谓筛选法就是从全集中将不合格的项全部删去,剩下的就是答案。
0 [9 ^. @. ], W' z6 l2 t7 l9 b: i: ]# J+ U1 Q( c" H  W; P
1: 求1-100之间的质数4 ^0 @# {+ E. G1 k; s
$ ]+ G. b% |  {- Y; g( f
    原理:先将2的倍数全部划掉,再将3的倍数全部划掉……直到将10的倍数全部划掉(10^2 = 100 )。剩下的就是质数.
. y2 M; m6 s- w5 _3 r0 n2 \
. |' {7 b4 T& U1 J7 _void fun1()0 h7 i0 L$ Q5 S5 F0 c' l5 Y
{6 T0 Z! `4 |- Z% P2 F  f
    int i, j;
* r6 S+ n) {3 F" m6 L    bool flag[100];7 Q' j( L/ u6 p* O
. g8 F- E3 c6 Z2 a
    for ( i = 2; i < 100; i++ )
0 {2 C- K6 I/ g4 p4 V) q2 m        flag = true;1 |! p& n/ ?. L, c; i
: j/ T$ ]. d7 B! t. S
    //下面开始划掉合数3 o! H& W$ O; u& q
    for ( i = 2; i < 10; i++ ) //因为合数的最小正因数不大于它的平方根
, R3 O2 R7 _! ~5 u    {3 p  E: y7 e7 t9 r4 C/ S
        if ( flag == false )
& P# M+ g7 c5 g            continue; //既然i已经是合数,它的倍数应该已经被划掉
6 L- H' A5 ?6 i8 e' X3 _7 z; I2 f: g        for ( j = 2; j * i < 100; j++ )//划掉i*j
8 x8 R+ v( L" \* {) |            flag[i*j] = false;
) s. l& H2 j* V/ v1 R: o    }- Z6 m; j- V9 E2 f5 i7 U: R

9 o5 @) z, ~% t3 H- n, N, ~    //输出结果
$ i0 L! n! p. I    for ( i = 2; i < 100; i++ )2 L: F7 }. j4 }7 j  Q
        if ( flag )# E8 I6 s" ?' H: w
            cout << i << ' ';2 R/ n1 u- s6 }" y4 Y
}
& D2 Z! ~$ ^' V% b! v1 {
( g% v' \( N! E0 f  i" t2: 30个人站成一圈,从第一个人开始报数,凡报到5的拉出去毙了,剩下的人接着从1开始报,直到只剩一人放掉。想活命该站哪?
1 y# Z0 G) `# P' G- u  V# h3 s- `! n  R
    这是个经典问题,解法就是模拟整个过程,有点类似于循环队列。4 _$ e1 H1 ?' k3 w: M

4 e2 r3 V: t3 i9 J  I; `    另外,为了程序上处理方便,可以假定所有的人都拉去毙了,然后看一下最后一个被毙掉的是谁。另一处为了处理方便而采取的措施是pos的初始值设为-1.很多时候,对问题的问法稍作变动,或者将初始值、加减变量的位置稍作调整,用程序处理起来会方便很多。2 a. L% E9 {( B% t( m: y. O

3 A9 M' P; p" N5 t: P5 Ivoid fun2()8 x( N. E, }/ H  _. b2 s
{
6 \6 Z0 d( q. Z; Q. |" W5 C" s8 E    bool flag[30];//标记第i个人的状态,false已被毙掉,true还没被毙掉
* E0 z& m: y; w+ W/ s# {
" i8 e6 c+ u- k5 \  n+ H% g    for ( int i=0; i< 30; i++ )7 i( U; B/ `2 \. x/ P
        flag = true;
3 ], Y+ r$ E) U3 H6 S- h2 a! b( M
5 Z5 w& M$ J6 a1 y2 S5 c: A    int n = 30;//还剩几个人3 m$ c2 `! X4 p: M' V
    int cnt;
: O8 O7 k9 P* m' c    int pos = -1;//初始值不一定从0开始,设为-1处理起来较方便. B+ R, {1 `9 {/ o
    while ( n > 0 )
0 ]: j' \1 q/ e+ E) z    {
0 Z7 ~7 v% O7 n1 G0 h0 M        cnt = 0;0 n8 g/ x, x% l2 k- e
        while ( cnt < 5 )# c3 {& o- n0 J
        {1 G6 u0 y/ v- K  K
            if ( ++pos == 30 )( C) ]0 [" f# W# \3 [! a
                pos = 0;; Z9 \" c5 L/ l- d8 X
            if ( flag[pos] )//此人还没被毙掉
, Z* w3 Y& Q- v# I( W8 g  n% w- j1 x3 q                cnt ++;& o& }6 ]5 P1 w4 p  H
        }
0 S' b4 Q0 @2 o( i& D        //退出时cnt == 5,pos指向报5的人
8 j( C  ]! F$ I        flag[pos] = false;//毙掉
$ D( Q- o& Z3 ]/ p! R, F  N        n --;//剩余人数减1
* P: \& G3 A. d& f* u" A    }
, G) c4 ?! M, Y2 S) n    //最后一个被毙的就是幸存者
; m- X' m) \4 v3 s8 V    //之所以加1是因为程序中从0开始计数,输出却以1开始计数
5 B# ^" W  @1 F  X7 i$ a    cout << pos + 1 << ' ';) z1 L' k* a; V$ t7 w: P* D
}- d' a6 o, J2 {/ I8 P
/ t/ O6 F) _# A. x
3: 一个数被5除余3,被7除余2,求此数最小为几。- x8 `1 O/ \4 ^( s( Z- w

8 H! z2 ?5 n( v  G- ?    筛选法不一定非要标记true/false,有时候也可以使用计数来进行筛选,这个问题就是一例。# _. Y& s$ a) v5 ]/ o
    首先,如果问题有解,则解必小于 5 * 7 = 35,只用在此范围内筛选即可。
$ [" P: M- [1 B  k, K    在程序处理上,如果一个数满足一个条件,就将计数值加1,最后计数值为3的即为所求。
4 a$ @+ i, O- ^) s; j- ?% A
" L: e1 u. ?0 E5 V# `void fun3()
4 `. X* h* x' I5 a: a7 p8 Y{
! Y# G2 Z5 l9 c: O. j    int a[105];//105 = 5 * 7" Y7 _/ v' X3 M0 o& m5 p! Y' `1 I
    int i;0 v* @+ N/ B: N  G  j
    //计数清0
& |7 V7 e* ?5 b! y% }# B" H    for ( i = 0; i < 35; i++ )
- `5 u4 e+ E% m  @  b& p& V$ t/ g        a = 0;
) }! N# h/ g; O2 }; r! z    //开始筛选, t% {- u1 d, A4 X
    for ( i = 3; i < 35; i += 5 )1 z. \0 R# u; N3 v8 a; m& M. y4 n
        a ++;: O2 n7 O' _$ Q. n( P3 V
    for ( i = 2; i < 35; i += 7 )
1 _2 f3 |' E9 s4 e        a ++;
8 i) c$ Y( n' S) j: A9 x2 t5 U7 ]2 C* n" z
    for ( i = 0; i < 35; i++ )
4 E8 g3 |- i2 `2 o9 B! R" W        if ( a == 3 )
+ V  Z4 h9 t  j$ I  E1 z" d        {/ P  R  X4 A$ z' [8 E2 l5 M& r6 E
            cout << i << endl;
; ?8 P* {3 C" q2 E' s& l            return;2 v+ M7 q+ D' c' Z2 T$ l/ v
        }
6 }# r/ s# ?+ d5 S$ V    //如果执行到这里说明无解
6 v1 b6 t' l/ c% s, ]7 G  P    cout << "No Answer!" << endl;& G" T6 z# X! _! }$ ]
}
+ f% `: ^" @7 r- _5 m: b4 [8 g# e) K" U9 q
( \) G% y- B# `* C1 O. G& u# Q3 _
6 @) d8 {0 l  w2 X. _总结:, b9 Q- A' `% Q6 |* G3 K
    筛选法的时间效率较高,但需要一个辅助数组,这就意味着对规模很大的问题不适用。例如第3个问题,条件多1个,需要的空间就翻几倍。解决的办法是:
; h1 V  V' c9 j& S8 G3 X2 h  n- v9 E1 R
for ( int i = 0; i< n; i++ )6 q0 f7 R7 N2 V+ N, P: d) u8 \
{3 K* t9 S( E7 _7 J. x
    if ( i % 5 == 3 && i % 7 == 2 && ... )& i, z: W1 O1 t' f+ e
        cout << i;! Z7 M2 @# H4 \% q
}. U& T- X3 x/ @
    但相应的,这样做速度就慢了下来。所以还得根据问题的规模来决定使用什么方案。7 R7 a& I" \5 q- ?: u7 y- O

2 t: B0 _# U0 o& z/ c7 g/ Q    总体来讲,对于可以条件判断较复杂,且根据前一个(不)符合条件的情况较简单的推出下一个(不)符合条件的情况,(不)符合条件的情况分布较稀疏的问题,用筛选法速度较快。如果第3题中加一个条件被2除余1,用筛选法就不太合算了。0 e# a/ ~: i9 ~$ o
* Z. w& y+ B$ L. X
    最后说明一下,此次给出的程序目的在于说明方法,在效率并不是最高的
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-1 19:41 , Processed in 0.374120 second(s), 57 queries .

回顶部