QQ登录

只需要一步,快速开始

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

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

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

7

主题

1

听众

43

积分

升级  40%

该用户从未签到

新人进步奖

跳转到指定楼层
1#
发表于 2004-6-8 16:42 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
所谓筛选法就是从全集中将不合格的项全部删去,剩下的就是答案。' I3 ]& i  y) B# K1 A, K! y, {
1 k* A7 F" T" u4 T& L0 u
1: 求1-100之间的质数
0 d7 `$ c8 B3 h$ u: a) e8 e; b$ k# l% \) [/ F; g) g4 g
    原理:先将2的倍数全部划掉,再将3的倍数全部划掉……直到将10的倍数全部划掉(10^2 = 100 )。剩下的就是质数.1 R" o! m- q+ @8 s* G1 Y
' t; \; {, A6 {, L8 z% i. W7 X
void fun1()
. `. F  ~  u% A: `{
- `; `! M9 J( o% R1 p( {    int i, j;
* N& X  n* S% u$ w    bool flag[100];! q- e1 r% ]( N! p" X! s
; M+ m7 i! L* `7 U) _; z- j+ M
    for ( i = 2; i < 100; i++ )
# [1 H! [, L7 p( M* V        flag = true;
8 T/ D: W' ]( m( x# y5 ?  N9 D; I# E1 U0 R
    //下面开始划掉合数
8 I0 M, _* I" d5 P  O: ]" i- X    for ( i = 2; i < 10; i++ ) //因为合数的最小正因数不大于它的平方根! n8 _( j  i/ ~: U8 \, `, {
    {' `1 Y% h7 K8 P+ d: a' p0 C
        if ( flag == false )" p2 o5 i& u5 U# y: S" B6 V
            continue; //既然i已经是合数,它的倍数应该已经被划掉9 ^: r- w9 y3 j0 M  R5 A; `
        for ( j = 2; j * i < 100; j++ )//划掉i*j  O# h% F& u, U' v# W( N! a
            flag[i*j] = false;. h' p9 h+ n: I
    }9 {# A3 L8 v3 m

) e: b1 p" _- ^" E* r  _- H' c; ^2 W' C    //输出结果
6 o+ g5 A9 o3 A# @    for ( i = 2; i < 100; i++ )5 X! d9 r: d2 j. o
        if ( flag )
) N$ G' G7 c0 d            cout << i << ' ';
7 ]7 }* ~9 V7 s2 {}3 S) R9 Z. s! H/ |2 a
! ^0 y, m8 K6 J' U* _4 r/ X
2: 30个人站成一圈,从第一个人开始报数,凡报到5的拉出去毙了,剩下的人接着从1开始报,直到只剩一人放掉。想活命该站哪?, ]& \" X) Z) N, l# ^- R# v2 L3 B: o

. J" A5 o! Y; g; ~' m  y# W    这是个经典问题,解法就是模拟整个过程,有点类似于循环队列。
' u$ y( Z4 t6 M- p0 f
8 L/ [) n5 I# I$ T' m0 \3 U    另外,为了程序上处理方便,可以假定所有的人都拉去毙了,然后看一下最后一个被毙掉的是谁。另一处为了处理方便而采取的措施是pos的初始值设为-1.很多时候,对问题的问法稍作变动,或者将初始值、加减变量的位置稍作调整,用程序处理起来会方便很多。
% ?7 Y' i, r7 Z0 I% t
& u! ^/ w4 T; J0 y  nvoid fun2()
+ _$ s2 g- h; V) E9 m) F  d{  ^2 Q8 E8 c+ h4 ]1 s! A
    bool flag[30];//标记第i个人的状态,false已被毙掉,true还没被毙掉
; C+ v$ |5 i; d
, H$ H& d$ H) O5 L6 x4 W  `    for ( int i=0; i< 30; i++ )7 s& }, K4 y# E8 @
        flag = true;9 J0 p& w! q+ O& D* X( _2 w4 R
% {/ l* B9 Z2 m( n( H; q8 K# ^
    int n = 30;//还剩几个人& @: G9 x  e( k& |0 P
    int cnt;
0 t$ P" \# [& D' S4 u$ f, p    int pos = -1;//初始值不一定从0开始,设为-1处理起来较方便
1 ?& B- r3 U3 @$ Q7 ~& X$ _4 f* ~! j    while ( n > 0 )  R2 k* w/ x1 H, F4 A3 B+ ~
    {1 x" r$ o7 `9 k2 @' N. c5 u5 @4 a! Q
        cnt = 0;  q6 z0 I# L5 X8 J
        while ( cnt < 5 )9 }' d2 w! v2 [6 D
        {
( k4 n! e7 M) Q            if ( ++pos == 30 )
2 n( v7 F' R, H9 T7 C( k5 x                pos = 0;* D. z2 C& \# r  ^2 d
            if ( flag[pos] )//此人还没被毙掉; J+ `) p; C. v! k( ^# H
                cnt ++;4 _3 h  g" _9 }6 V5 Q
        }
. {6 _8 h  i' c/ e, s% i0 [& [        //退出时cnt == 5,pos指向报5的人( c" z  ]! {: ^. k5 B. x
        flag[pos] = false;//毙掉
3 p# Z5 O8 o8 s) l. f) o        n --;//剩余人数减1
* @7 s3 w2 v6 ]    }3 Y/ P  h9 z9 z9 K' o3 q
    //最后一个被毙的就是幸存者; b4 f7 q  c, K$ C# Q
    //之所以加1是因为程序中从0开始计数,输出却以1开始计数
2 z) X8 R6 y$ {$ n    cout << pos + 1 << ' ';
9 K8 ]$ M3 g4 \( o- q/ A}$ q7 X+ j2 [2 W% D1 b' i; q
2 ~6 Q+ J. z2 E2 Q" ~0 v
3: 一个数被5除余3,被7除余2,求此数最小为几。
1 E9 _- w* o3 B5 ]2 n  J3 t  O9 k( L) @2 _$ N
    筛选法不一定非要标记true/false,有时候也可以使用计数来进行筛选,这个问题就是一例。7 }. v# v" a' x9 Y, ~  S
    首先,如果问题有解,则解必小于 5 * 7 = 35,只用在此范围内筛选即可。9 `) q; k; b, W+ c  ?: d! ]
    在程序处理上,如果一个数满足一个条件,就将计数值加1,最后计数值为3的即为所求。# {! Y( I" T% ]3 N/ S' ^

& ^# Q4 [9 N5 _0 ]& {) Qvoid fun3()% M% M# R; ]" D5 s
{
: f  i  J! k1 c; D) E; [3 _    int a[105];//105 = 5 * 7
" c1 i2 o. u; k2 _- Q0 x    int i;
4 E; p# E, W5 [) W+ b    //计数清0
1 q/ @! I2 v& P8 r; j5 X: D, o! R1 C    for ( i = 0; i < 35; i++ )# V3 k+ E% h: _- P
        a = 0;1 n& U% L2 i1 Z
    //开始筛选" n9 e/ L+ b: `. L2 n( e
    for ( i = 3; i < 35; i += 5 )3 c) q' K) j! k/ c- C
        a ++;4 n; @: M3 ?) H% |6 Z7 v. ]
    for ( i = 2; i < 35; i += 7 )
$ q" W; L3 B6 p9 y' @: O9 w        a ++;) q* C% S. q  O! h7 I
5 X0 ]2 }0 a  r! U7 N
    for ( i = 0; i < 35; i++ )7 X3 h& C3 f  A/ ~7 G
        if ( a == 3 )
, G# N) F- y( {        {
: q7 V% j# p: v; a9 _1 z            cout << i << endl;% x! k4 g( F9 j+ {6 D4 x
            return;6 X5 ]" o* Z9 U# Y8 b, K
        }
' I6 I! j% K; y1 ], ]4 F    //如果执行到这里说明无解4 F8 B+ c  i% Y/ v
    cout << "No Answer!" << endl;
+ o: Z0 Y% O3 X) R}0 j( v0 h" a9 x" e  E
5 a  q( X9 N' o' Z1 \

+ ?' @  R- d4 a9 T6 n3 j总结:
% s5 R% R2 C) k5 }' P' P% H    筛选法的时间效率较高,但需要一个辅助数组,这就意味着对规模很大的问题不适用。例如第3个问题,条件多1个,需要的空间就翻几倍。解决的办法是:
2 @7 z3 o4 e8 V" n1 N% h2 f: W4 Z4 ?: c1 S8 g
for ( int i = 0; i< n; i++ )2 ?# o- F4 l; c1 K$ q: y
{+ q- {; `2 M* \9 ], p8 J
    if ( i % 5 == 3 && i % 7 == 2 && ... )
  s- r/ I' G* Z; \' f' o        cout << i;
/ r* @! x0 C" m' b/ L( Y, {}2 ]3 I9 m- ~3 ]& ~% _, f' ^
    但相应的,这样做速度就慢了下来。所以还得根据问题的规模来决定使用什么方案。5 ~' Q7 d+ o9 Y$ {) O

9 T, s' g6 a, j7 m* a" \/ O$ p  s    总体来讲,对于可以条件判断较复杂,且根据前一个(不)符合条件的情况较简单的推出下一个(不)符合条件的情况,(不)符合条件的情况分布较稀疏的问题,用筛选法速度较快。如果第3题中加一个条件被2除余1,用筛选法就不太合算了。
5 t8 t3 g! G( S1 t7 E7 K* K3 Y& z% d, V7 E8 m8 T) M' 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 04:50 , Processed in 0.444853 second(s), 58 queries .

回顶部