QQ登录

只需要一步,快速开始

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

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

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

7

主题

1

听众

43

积分

升级  40%

该用户从未签到

新人进步奖

跳转到指定楼层
1#
发表于 2004-6-8 16:42 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
所谓筛选法就是从全集中将不合格的项全部删去,剩下的就是答案。. E1 _) `' m& g+ b; X' Q3 h& t/ y: l

/ T8 a( L- \( P. P% c1: 求1-100之间的质数1 l( Y: g, U) D

( ^6 t9 D/ V0 L4 o! }. @6 ?    原理:先将2的倍数全部划掉,再将3的倍数全部划掉……直到将10的倍数全部划掉(10^2 = 100 )。剩下的就是质数.
; g# q7 w4 k/ M2 Q4 M8 |& T
4 j( c# j' F$ r8 u2 Mvoid fun1()
5 L; a  |! N7 [0 R# j{
  c: T/ k; w# R/ T3 L* [    int i, j;
! k/ J8 v! S8 U& o; f2 ]    bool flag[100];
! Q. z3 \" A+ W9 z. [/ C$ k; Z% N0 u5 k* v& t" E
    for ( i = 2; i < 100; i++ )* o9 g4 k6 h( u1 u' r4 s
        flag = true;
% ^* ^4 W/ ^6 C1 E
3 U# i6 z# M$ X3 p8 B9 B    //下面开始划掉合数
1 j$ L& L7 c9 I0 S7 \) S. }' q    for ( i = 2; i < 10; i++ ) //因为合数的最小正因数不大于它的平方根/ ?1 X( l& \( M( u2 Q7 ]0 E* ]
    {/ }) g2 u# ?4 |( N0 O
        if ( flag == false )
1 `4 J, @- h( s            continue; //既然i已经是合数,它的倍数应该已经被划掉* R7 c9 C, V2 o4 p1 d
        for ( j = 2; j * i < 100; j++ )//划掉i*j
1 X- I' w! ^2 V; {( z            flag[i*j] = false;7 h# h7 i8 ]4 C: ^- ^$ b5 d/ j# `
    }
8 k/ l/ S* y0 \3 i! M$ D& j4 e, N! b5 Z; {" n: v
    //输出结果& I, d, w% _( [; y" }
    for ( i = 2; i < 100; i++ )
& n8 Z2 f9 Q2 E+ R9 g* z% ?5 o        if ( flag )
# P/ q/ R( J9 T+ a$ d/ `# ], ?            cout << i << ' ';' @( n2 d* T9 c! S
}
+ w( E& J3 q. n* ]# S$ }! t( E' Q, |9 o) T" u' J
2: 30个人站成一圈,从第一个人开始报数,凡报到5的拉出去毙了,剩下的人接着从1开始报,直到只剩一人放掉。想活命该站哪?: D3 C5 x/ H& B6 G8 a" V, u4 G

/ n3 ^4 w& A- |$ Q# ~; }- A$ d    这是个经典问题,解法就是模拟整个过程,有点类似于循环队列。
) n6 e5 w/ @% s4 B, d' L- C, Z2 D
9 ^! d4 ?3 V  ?2 i) |% f1 x    另外,为了程序上处理方便,可以假定所有的人都拉去毙了,然后看一下最后一个被毙掉的是谁。另一处为了处理方便而采取的措施是pos的初始值设为-1.很多时候,对问题的问法稍作变动,或者将初始值、加减变量的位置稍作调整,用程序处理起来会方便很多。8 }0 u6 Z) d$ x

/ s7 m( c, t. R" m7 z- pvoid fun2(), m- H2 f3 E5 {' d) Y& S/ V) C8 \
{
% J8 u- R" R# V; k6 |9 V. i    bool flag[30];//标记第i个人的状态,false已被毙掉,true还没被毙掉
; V! ]# Y2 ^7 U- G7 q
  A' R: i/ C/ b4 X0 P    for ( int i=0; i< 30; i++ ), j' j. V9 |: Z
        flag = true;
, K  j4 }5 t: t) m, W/ K6 a2 s) [: j: I: ?8 p
    int n = 30;//还剩几个人$ b5 h7 H( ~8 c( i# ~
    int cnt;/ y3 L3 [: ?0 |/ S) H5 `; X
    int pos = -1;//初始值不一定从0开始,设为-1处理起来较方便$ J; x7 e* N0 L( ]  Q7 c% D
    while ( n > 0 )  H5 P& J, W4 L. P* D" m5 {; T0 J0 v
    {
) d: Y% h7 B) \2 B4 L& `        cnt = 0;* M3 C9 q5 k) J  N
        while ( cnt < 5 )
/ H) i) d+ v) B0 w        {- S% \0 ^0 E9 t" `  I
            if ( ++pos == 30 )/ d! i) k& ]7 I) q6 k
                pos = 0;: {  ?+ w9 Y' ]
            if ( flag[pos] )//此人还没被毙掉" f  X0 u$ w( B) d( g
                cnt ++;8 m/ @* Q% r- ^2 S# ?
        }% n* U' j( l4 x
        //退出时cnt == 5,pos指向报5的人
. ]) D+ d2 u8 Z, c0 `5 n        flag[pos] = false;//毙掉' K! X8 \1 p# ^: L- b* ~
        n --;//剩余人数减1
. |% |; ^" o7 [+ P    }8 F! Q7 i3 K- z0 W
    //最后一个被毙的就是幸存者
9 h" F3 G( {7 a* C) z6 q1 x3 ^7 @    //之所以加1是因为程序中从0开始计数,输出却以1开始计数
* \8 x" E# P; F    cout << pos + 1 << ' ';; n8 P& s$ g3 m% W( Q: o; m! N
}& I, p* d5 k/ u% c+ u
8 A4 {! Y) y  T9 I
3: 一个数被5除余3,被7除余2,求此数最小为几。3 v8 j+ Y- X$ d; d' m$ E$ v& K

/ M9 ~+ V1 r+ G* C    筛选法不一定非要标记true/false,有时候也可以使用计数来进行筛选,这个问题就是一例。
! }$ ]. P, h8 e5 Y8 [    首先,如果问题有解,则解必小于 5 * 7 = 35,只用在此范围内筛选即可。6 V7 N5 v- K$ v% M/ R8 x
    在程序处理上,如果一个数满足一个条件,就将计数值加1,最后计数值为3的即为所求。
! Q( E1 c0 s0 V/ v1 l0 t" Z" D$ v
2 J0 N5 z4 y, a$ n* T' Evoid fun3()
- ]" R0 c. l2 r8 n% o; `{# o7 P, M% N! Z, K% A
    int a[105];//105 = 5 * 7
7 x/ f3 P8 }: ?0 Z* h: y. J    int i;
/ G' l1 G2 @4 ~5 V& Q    //计数清0- Q8 f5 _5 }0 D0 z. Z" ]
    for ( i = 0; i < 35; i++ )
& `1 j7 P  R( e        a = 0;9 X2 {0 @# l6 z4 g6 H8 R% \0 s! J
    //开始筛选0 d' [- {" |; y* I+ \3 d! ^1 Q
    for ( i = 3; i < 35; i += 5 )/ k# c( E/ F4 r' R
        a ++;9 |6 x- j* _) H* E7 C
    for ( i = 2; i < 35; i += 7 )
' A( o& Q, o) `8 d) y$ j        a ++;
$ _6 {; q" t9 c; H6 B& f: x
, k3 e( c- @# q' ?    for ( i = 0; i < 35; i++ )7 c1 Q8 j. M5 H& ?# T6 z
        if ( a == 3 )2 A# T( Z$ L) \% }& \
        {
: k5 o. u1 m- c) \7 d! L7 U) v0 a            cout << i << endl;: h& [" s/ {$ I3 o& R
            return;
' {7 P* D" p4 W9 u' O; n+ b        }* c+ ~# u  ?2 i" S: F% S7 T  _9 `
    //如果执行到这里说明无解$ Z5 T  {& D3 N+ k6 H9 |
    cout << "No Answer!" << endl;" Y  _6 G1 D$ B# i
}7 O, q/ X# N# m8 Y& x2 s
$ I6 K, t4 g7 G

5 [5 L4 p$ ^: I: l% y* P9 |' q总结:- n% v& h, C. H
    筛选法的时间效率较高,但需要一个辅助数组,这就意味着对规模很大的问题不适用。例如第3个问题,条件多1个,需要的空间就翻几倍。解决的办法是:
3 x4 b9 o" }, R; H- T' N/ |% L1 I
- v2 O- X7 b+ l! y" f9 {7 pfor ( int i = 0; i< n; i++ )3 b# z4 `, k& [2 |
{1 ~. U0 H7 Z; Q' [
    if ( i % 5 == 3 && i % 7 == 2 && ... )9 @2 t" J$ A* U
        cout << i;
* f3 {4 c+ ~& Z; H* |; b}
. u* ^, K- E* h    但相应的,这样做速度就慢了下来。所以还得根据问题的规模来决定使用什么方案。( L9 F  ~( g  H! ^/ E, E# _  y
7 l6 J  a4 j) v- U
    总体来讲,对于可以条件判断较复杂,且根据前一个(不)符合条件的情况较简单的推出下一个(不)符合条件的情况,(不)符合条件的情况分布较稀疏的问题,用筛选法速度较快。如果第3题中加一个条件被2除余1,用筛选法就不太合算了。/ ~: r5 h& U. V, y! \* F1 m" e
' x1 `/ v- {3 i2 L* q, u
    最后说明一下,此次给出的程序目的在于说明方法,在效率并不是最高的
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 06:45 , Processed in 0.453004 second(s), 51 queries .

回顶部