QQ登录

只需要一步,快速开始

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

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

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

7

主题

1

听众

43

积分

升级  40%

该用户从未签到

新人进步奖

跳转到指定楼层
1#
发表于 2004-6-8 16:42 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
所谓筛选法就是从全集中将不合格的项全部删去,剩下的就是答案。
( n3 |0 n6 }# M6 a( t* A0 D& t) u
. D4 Q  x& j# ^4 ^) p0 ~( Q1: 求1-100之间的质数
! g0 _. o" k- U6 S+ a2 ~- e7 F
/ O2 k5 I. d. s# H( s0 H- s    原理:先将2的倍数全部划掉,再将3的倍数全部划掉……直到将10的倍数全部划掉(10^2 = 100 )。剩下的就是质数.* t3 H+ ?4 N& [- F4 l# [" k7 L2 Z
8 N, J/ |  [* g- x
void fun1()
) h/ u: K7 q$ r8 j6 d  N6 T: ^{
7 o- x& I) l3 g9 L    int i, j;
; M' \! `" u0 O+ }& E    bool flag[100];7 j0 a9 \( q3 c; r7 S8 t% ]: `! t

# w' B" e" L$ a* z' M    for ( i = 2; i < 100; i++ )
' R. X! k5 I3 D: u( ~8 L/ r4 s) i        flag = true;
, b( z( I# {1 r1 \' q% R
0 x' j6 c! v* V. A* o4 n9 v    //下面开始划掉合数  W( l8 @  x0 Q. X: N, v0 Y9 S
    for ( i = 2; i < 10; i++ ) //因为合数的最小正因数不大于它的平方根
7 H. f8 Q! b: H! L9 e* D5 t5 F1 O    {3 F1 R; p" Z, p
        if ( flag == false )" @" H5 g& n6 y6 V; b# |
            continue; //既然i已经是合数,它的倍数应该已经被划掉) Q6 E/ X: `9 f+ T
        for ( j = 2; j * i < 100; j++ )//划掉i*j; J2 [' h/ S0 O) i1 S; U
            flag[i*j] = false;
+ z: ^- W) a& \# T+ u    }0 a5 R3 c) o2 P/ ]9 {% Y
8 I3 s5 m+ F& {& J
    //输出结果
+ w7 J$ G, Y! C; m1 ~6 R    for ( i = 2; i < 100; i++ )
. y( ^5 d2 \6 k( D9 l7 w        if ( flag )9 ]8 Y) S9 _; W, Z  c$ G( x' H
            cout << i << ' ';! D3 x! }# n' Z- I! B
}1 x/ A4 d8 Y  L3 G; a
+ t, j: S+ z, u# E3 m, M5 ?/ _
2: 30个人站成一圈,从第一个人开始报数,凡报到5的拉出去毙了,剩下的人接着从1开始报,直到只剩一人放掉。想活命该站哪?
& D* X) X3 ]* J2 t; M  V3 q* n; w: B( M7 W$ ^
    这是个经典问题,解法就是模拟整个过程,有点类似于循环队列。
+ ^9 u5 C$ w& s* U9 R/ D4 W" A7 f- z/ A' \; o
    另外,为了程序上处理方便,可以假定所有的人都拉去毙了,然后看一下最后一个被毙掉的是谁。另一处为了处理方便而采取的措施是pos的初始值设为-1.很多时候,对问题的问法稍作变动,或者将初始值、加减变量的位置稍作调整,用程序处理起来会方便很多。( e+ {2 j" @8 h/ ]) U1 N

9 N; l/ ~8 O$ j8 o) h: Xvoid fun2()
/ T0 e# I  |% a1 [; F{9 O( W8 [' z* a' n/ k. A( M' N
    bool flag[30];//标记第i个人的状态,false已被毙掉,true还没被毙掉
+ R% u& M; T7 ?  |
; a3 |# }6 s# N. h: R; a/ V- j    for ( int i=0; i< 30; i++ )
2 ^2 q- B/ x) k7 |) I* ~        flag = true;3 f3 A/ d+ N1 L; r4 n
7 |5 t" J' Y3 {
    int n = 30;//还剩几个人% F; f5 O9 [- w7 ~
    int cnt;% X2 d4 g3 R+ z- L+ L* U0 u) ]
    int pos = -1;//初始值不一定从0开始,设为-1处理起来较方便
  R# C; v$ X4 J, {    while ( n > 0 )* X- J( r/ @; z2 t  d3 c2 h
    {9 p8 G% R; {* }6 w0 k
        cnt = 0;5 |; Y  K6 T& \
        while ( cnt < 5 )7 {9 }, b$ `& j' S% s
        {
) x! q, T% Y% O9 C- `            if ( ++pos == 30 ). D" `5 |( I3 x  m* _
                pos = 0;
2 J, S! c2 p# P, s4 T' M" J5 e            if ( flag[pos] )//此人还没被毙掉
3 T, f! o7 M- b8 T9 m* F) N                cnt ++;7 A3 E/ u: K6 N1 I& ^
        }$ R7 S# {8 n% ]- F& }
        //退出时cnt == 5,pos指向报5的人
" b% y. K/ j6 J2 ]/ n( |        flag[pos] = false;//毙掉$ ^$ C) p+ i. ~. N! j2 A! P; l
        n --;//剩余人数减1
! `& t4 F5 B0 o) `. V: i. l9 c    }3 T  A( s! k2 u
    //最后一个被毙的就是幸存者
" O% ~& m9 k* J% @    //之所以加1是因为程序中从0开始计数,输出却以1开始计数
- G) F4 G3 S1 B' I: D, h. r* H! [" t    cout << pos + 1 << ' ';
/ j, q' b! f% f* v}
* k9 M: ^# {6 ^( X
4 p; d! W: T/ }+ w& s3: 一个数被5除余3,被7除余2,求此数最小为几。
5 F' @+ ^% g- H6 g- S; O* i4 K6 u0 U& v
    筛选法不一定非要标记true/false,有时候也可以使用计数来进行筛选,这个问题就是一例。
3 [& V5 E+ r5 [5 u( k    首先,如果问题有解,则解必小于 5 * 7 = 35,只用在此范围内筛选即可。" S+ ?2 l/ g. h( m
    在程序处理上,如果一个数满足一个条件,就将计数值加1,最后计数值为3的即为所求。7 c& U3 G, [1 D1 P% Q

  K0 Y, [' N- e( L0 n- xvoid fun3()
* p  p$ g7 U/ U{
- I7 F9 A0 ]# Y    int a[105];//105 = 5 * 7
& L2 y$ S6 n1 d: M; O    int i;# O6 g$ s8 L: o) u
    //计数清0, \5 j6 w* [2 ^0 E& ]0 n( R
    for ( i = 0; i < 35; i++ )+ u- s. [6 h7 z9 H! B
        a = 0;, p% L; A: Z1 M2 u- O" O
    //开始筛选
6 P" `$ \( z# R% F# W4 D    for ( i = 3; i < 35; i += 5 )+ E3 l$ h; L2 M1 k
        a ++;; Z) [: C$ [! K, V) Y
    for ( i = 2; i < 35; i += 7 )2 a+ t6 g+ o# H
        a ++;- B, G& g/ i/ k

) F/ Q* R% F8 g# H* Z3 g& p    for ( i = 0; i < 35; i++ )
1 Z# r8 n) T) J% C1 e; t- J; z        if ( a == 3 )
& m1 B$ K: y4 m0 Q- k& T$ Z        {1 z$ `- W  G" `' X
            cout << i << endl;+ _) ^; s& }4 ?9 m8 z) w5 B9 h
            return;1 {9 X2 @. a- I  t8 q
        }
, b( P, d3 t+ W+ D9 p% H    //如果执行到这里说明无解5 Y3 @: p" q5 w6 I# x' _
    cout << "No Answer!" << endl;
: E+ r7 B1 B; M9 R3 i  X}
3 l" N/ A) \9 ]$ a& y" f
0 i1 S4 R8 v5 h, Q
0 @. k2 X5 S0 r2 {总结:
+ o) K4 O2 y- h. r; @" Z- y    筛选法的时间效率较高,但需要一个辅助数组,这就意味着对规模很大的问题不适用。例如第3个问题,条件多1个,需要的空间就翻几倍。解决的办法是:" G. w3 x6 g! d, ~' W* N, V9 @
: ?) n% b& p- w' D/ \8 v
for ( int i = 0; i< n; i++ )
9 y6 t( }8 |  R{( F5 j' q* ]& f( D( g
    if ( i % 5 == 3 && i % 7 == 2 && ... )- `! W$ g$ U6 \& |" l3 F
        cout << i;) D* x- O) T3 V- R6 |& I
}! W$ |, W3 P% Y) m$ T
    但相应的,这样做速度就慢了下来。所以还得根据问题的规模来决定使用什么方案。
2 Z+ ?: o; \0 z: ]# [* M0 V2 `( P& g: C, z: e6 N; Q* O
    总体来讲,对于可以条件判断较复杂,且根据前一个(不)符合条件的情况较简单的推出下一个(不)符合条件的情况,(不)符合条件的情况分布较稀疏的问题,用筛选法速度较快。如果第3题中加一个条件被2除余1,用筛选法就不太合算了。
: M. m3 u2 y8 F! S1 w8 W; W4 j0 Y0 G
    最后说明一下,此次给出的程序目的在于说明方法,在效率并不是最高的
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-4-20 01:19 , Processed in 0.350843 second(s), 58 queries .

回顶部