QQ登录

只需要一步,快速开始

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

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

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

7

主题

1

听众

43

积分

升级  40%

该用户从未签到

新人进步奖

跳转到指定楼层
1#
发表于 2004-6-8 16:42 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
所谓筛选法就是从全集中将不合格的项全部删去,剩下的就是答案。
0 n! n6 }4 w' q# P! h) {4 l
& [3 Q1 ~- E  c1: 求1-100之间的质数  w8 C% a3 H; F& R! Q. |) |

: x7 k& X: m' F- Q! ?- v  m% \    原理:先将2的倍数全部划掉,再将3的倍数全部划掉……直到将10的倍数全部划掉(10^2 = 100 )。剩下的就是质数.7 g& Y$ K/ ~* z9 H+ X% F
5 D$ I+ n4 V5 m5 B
void fun1()
' S8 i8 z; v; y8 U. Z{
2 n: e7 R- I2 o+ y    int i, j;+ p+ `( `1 ~, P. H% \" T
    bool flag[100];
6 j  w! ^* e* r2 P
0 T# u" P# N6 u- h0 C    for ( i = 2; i < 100; i++ )
" @' d! t! Y  z6 I3 G, y- Z        flag = true;
/ H& A$ @; I4 ^. S5 |  F4 j4 H0 ^
! G6 R, Y2 @: e/ h    //下面开始划掉合数6 a1 c9 P5 V( ~3 p
    for ( i = 2; i < 10; i++ ) //因为合数的最小正因数不大于它的平方根3 x8 l4 `) y: q) ^! D
    {
0 v4 w: S, R6 c$ H* S' G. `        if ( flag == false )
. F( h7 \- P: A& o$ C* ]: G            continue; //既然i已经是合数,它的倍数应该已经被划掉0 I' D0 M0 S5 l; z: D
        for ( j = 2; j * i < 100; j++ )//划掉i*j% h. L2 p9 X# [# M! a" |; a
            flag[i*j] = false;# Q' W; @% X" c+ R3 ]3 L( s  |4 a
    }
/ q1 H5 R; s- U# o" D$ h: ^1 G( ?6 t+ H, |2 y/ q* t6 k# l, K! ?3 {" y
    //输出结果
% I! u. V; `: Y, o; x0 j    for ( i = 2; i < 100; i++ )( s4 p8 N4 g3 }4 H/ h
        if ( flag )* w! k! R) X8 c. d7 E. {
            cout << i << ' ';
9 G: D, D2 Z3 k}
7 E1 v5 U" s1 c# B- u, Y- X  A* l' m$ O- [! ?& B
2: 30个人站成一圈,从第一个人开始报数,凡报到5的拉出去毙了,剩下的人接着从1开始报,直到只剩一人放掉。想活命该站哪?
. A/ w- S. ^/ E' ]% O- z5 e; r2 z7 s. h8 ~. ^; e+ N& y" [! r. D. @
    这是个经典问题,解法就是模拟整个过程,有点类似于循环队列。
; P" S) O. F$ _1 R& T- I2 n3 {" ?# Z, ^% |6 s+ l
    另外,为了程序上处理方便,可以假定所有的人都拉去毙了,然后看一下最后一个被毙掉的是谁。另一处为了处理方便而采取的措施是pos的初始值设为-1.很多时候,对问题的问法稍作变动,或者将初始值、加减变量的位置稍作调整,用程序处理起来会方便很多。
: @5 D! G( s, Z9 y3 g+ A% ]
$ B' V  g- ?  L! Q. F6 G$ C" @void fun2()0 j) H7 P6 l) u% l* Q
{
' j6 e1 ]* k- Z    bool flag[30];//标记第i个人的状态,false已被毙掉,true还没被毙掉9 F( A6 I9 p1 [1 k4 K

% \; {  j2 n9 L" o- K    for ( int i=0; i< 30; i++ )
! M, ]; \8 k/ O# v) y1 ?$ \5 h$ i( C        flag = true;+ U+ h! t1 O% l- }) J$ u! `
, V1 R3 t6 p" F* v  h& K7 T
    int n = 30;//还剩几个人
4 _* r( [/ }: d# I9 }% V9 f+ f) Q8 T    int cnt;
' B) ?, a2 D# v) x    int pos = -1;//初始值不一定从0开始,设为-1处理起来较方便. K% `8 e) [7 A  C' X0 C- Q
    while ( n > 0 )
0 `; ?7 c  n) I$ c" a    {" t. T: z- i+ L3 W- W5 b
        cnt = 0;
9 y& O9 i# T/ F0 W        while ( cnt < 5 )
) z, b) l2 s, p        {
% b: o  \' F8 k" f0 u            if ( ++pos == 30 )
4 @) @& T. O0 i3 M                pos = 0;% J, v6 O8 k. v! {# H5 o& p& m
            if ( flag[pos] )//此人还没被毙掉
4 f5 P7 t; `/ i4 T4 g4 V                cnt ++;* ]7 [- M# M; `( `/ d
        }+ Y; l/ i) K* O5 a1 h2 |
        //退出时cnt == 5,pos指向报5的人
2 A: Q$ ?& B$ l' _4 x2 z, v' @        flag[pos] = false;//毙掉: }2 t. C! V3 \* Y
        n --;//剩余人数减1, c% r, x5 b) r! Z
    }+ y8 p4 S: W' U7 a; P+ O1 v
    //最后一个被毙的就是幸存者+ Z& R) G2 X- Z3 ^" A
    //之所以加1是因为程序中从0开始计数,输出却以1开始计数# J" O; H% ?* i- }8 s$ N
    cout << pos + 1 << ' ';
: R& A# _* R; u; V) B+ {! H}# G) T4 _) [# T. O

8 U5 V! B! ]. B1 L; H8 b3 c" v3: 一个数被5除余3,被7除余2,求此数最小为几。
4 C% m( ^" p; C; h% N" T7 g2 _3 Z. @) C, k5 c1 e! T" T$ |
    筛选法不一定非要标记true/false,有时候也可以使用计数来进行筛选,这个问题就是一例。! Z% q- C" s/ t0 d
    首先,如果问题有解,则解必小于 5 * 7 = 35,只用在此范围内筛选即可。
& S, M4 Z, R3 }5 M) T- |    在程序处理上,如果一个数满足一个条件,就将计数值加1,最后计数值为3的即为所求。
4 g+ w8 v+ z- b( T# D) P1 g4 g* J$ C$ ^1 A0 K8 T
void fun3()
* }& z- M4 I( U+ {{$ H9 d1 y; I4 X2 K: Q
    int a[105];//105 = 5 * 7
) K0 f# A2 K: h( p    int i;; \7 W. x* p  p9 D; k, `6 `9 L( U: T* Q
    //计数清0
  U. m2 o% k; o6 c9 q# ^    for ( i = 0; i < 35; i++ )# l- G3 H8 d( y) `
        a = 0;
9 s/ \7 |9 {' T4 o    //开始筛选2 U/ @. a/ {: e) G" I5 b
    for ( i = 3; i < 35; i += 5 )3 Y2 Z/ c$ g; _1 g, G
        a ++;1 R8 }: R! g4 U( U" m; [( c4 `4 d) |7 b
    for ( i = 2; i < 35; i += 7 ); H4 \; W: }: N$ l1 u
        a ++;- i9 ?7 \1 L7 A% P3 W6 |- j
! |, s& _# `! p5 c9 f, t
    for ( i = 0; i < 35; i++ )
- t1 O  V! w6 ^        if ( a == 3 )9 d5 N; Z* J+ p5 z6 {, w
        {" b2 x  h" D+ N% v, n
            cout << i << endl;
0 |0 B; y7 i, h0 k: g8 ?1 G# ?            return;
/ l6 z8 m- \: {1 E8 C        }
( G& K7 m. E4 G4 E    //如果执行到这里说明无解- t: t/ k; K& r* r9 G
    cout << "No Answer!" << endl;! ^0 |7 e* a# b$ _& t7 Y: o
}
' s0 c1 I# r, s# \  f, ^7 U) V4 Y/ ?9 [& h& A/ \4 Z+ e& V
9 |4 {  F' D: V: j$ @" d8 f! m' T
总结:6 C, z/ ?& _# L3 B
    筛选法的时间效率较高,但需要一个辅助数组,这就意味着对规模很大的问题不适用。例如第3个问题,条件多1个,需要的空间就翻几倍。解决的办法是:
, b, T9 m0 y  J+ w% ~/ C
$ r0 V0 \8 F7 _5 Qfor ( int i = 0; i< n; i++ )# b) y" @" X. _' b
{4 f, I9 m$ u* [8 p" }
    if ( i % 5 == 3 && i % 7 == 2 && ... )* T/ F3 ~/ @1 d8 e  I% t
        cout << i;
; S0 l8 g! S( V}
1 G! h. I: k' ^    但相应的,这样做速度就慢了下来。所以还得根据问题的规模来决定使用什么方案。" e( o5 a( p( p# U

$ r+ S- |3 g* r& k# X    总体来讲,对于可以条件判断较复杂,且根据前一个(不)符合条件的情况较简单的推出下一个(不)符合条件的情况,(不)符合条件的情况分布较稀疏的问题,用筛选法速度较快。如果第3题中加一个条件被2除余1,用筛选法就不太合算了。
- `) h8 x7 N* O  a% z7 O
$ X. L/ n, E2 q5 O4 t    最后说明一下,此次给出的程序目的在于说明方法,在效率并不是最高的
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-6-13 08:32 , Processed in 0.606556 second(s), 58 queries .

回顶部