QQ登录

只需要一步,快速开始

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

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

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

7

主题

1

听众

43

积分

升级  40%

该用户从未签到

新人进步奖

跳转到指定楼层
1#
发表于 2004-6-8 16:42 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
所谓筛选法就是从全集中将不合格的项全部删去,剩下的就是答案。. H4 x4 t5 X0 T0 I& e. M2 k+ O

# _) _7 b0 m# [% M3 f1: 求1-100之间的质数
+ ]& d% Z1 E$ @- R6 w* E; ?* a9 l4 ], ^7 M
    原理:先将2的倍数全部划掉,再将3的倍数全部划掉……直到将10的倍数全部划掉(10^2 = 100 )。剩下的就是质数.. z6 p/ Y, T/ x7 _4 |9 P& N
0 c& j; D. \# v8 i0 G0 h
void fun1()
& Y  r5 W; L1 R{
% |9 @5 f' A4 d$ t' a    int i, j;2 I+ n# J* G, n. _( \1 v! @; z
    bool flag[100];
* D9 W3 D- }7 I5 D" {' A, g+ `* U+ D) a; m3 k* w
    for ( i = 2; i < 100; i++ )# a" q" f7 P6 Z9 f$ c4 i; s; ^! \# `( j
        flag = true;
: D* i: e, G7 `$ l; ?( ~/ V; |+ z; f9 N1 G* A+ ?6 J
    //下面开始划掉合数
) Y: P( x. |: c/ e* V$ g. q    for ( i = 2; i < 10; i++ ) //因为合数的最小正因数不大于它的平方根
0 q0 ]* {& o- u- k  a# z4 i1 H. D    {
- `6 E$ l7 R  K1 A. P        if ( flag == false )) }, X3 C. ^; I9 Z) ?( @  O
            continue; //既然i已经是合数,它的倍数应该已经被划掉
& D2 k; i0 x% a+ t! \) `3 }. o        for ( j = 2; j * i < 100; j++ )//划掉i*j( }) e+ ^8 z$ }+ q7 K2 l2 _
            flag[i*j] = false;5 L# n5 q' S4 \
    }
: i+ y: R& P+ c0 f: _4 L
( U5 j# M) t7 h1 ~    //输出结果
& z+ c7 G/ y+ }- @" }: @    for ( i = 2; i < 100; i++ )& R3 H6 w& x7 S% v  P: N( A5 @. s; ]
        if ( flag )
' N! v- \  u9 m- v: L            cout << i << ' ';
5 k2 s* H3 c* C$ d7 s}4 c2 a3 V2 L* c, ]7 h. M  V$ `8 y
, D% l7 D: d( u8 p
2: 30个人站成一圈,从第一个人开始报数,凡报到5的拉出去毙了,剩下的人接着从1开始报,直到只剩一人放掉。想活命该站哪?  N" _4 e9 S5 i: r( |% h. |

" w( w1 Y$ Z) D: }    这是个经典问题,解法就是模拟整个过程,有点类似于循环队列。( U4 n* k9 `" `1 j/ @0 P6 @

% O* s0 o& p8 t9 ?" P    另外,为了程序上处理方便,可以假定所有的人都拉去毙了,然后看一下最后一个被毙掉的是谁。另一处为了处理方便而采取的措施是pos的初始值设为-1.很多时候,对问题的问法稍作变动,或者将初始值、加减变量的位置稍作调整,用程序处理起来会方便很多。
6 r. d4 Z! K' H7 [
. f1 y- a$ Z( b2 v, {0 qvoid fun2(): S3 p' ^. M% e. J$ r' z% N8 R
{, a& B; d3 l3 _% Q
    bool flag[30];//标记第i个人的状态,false已被毙掉,true还没被毙掉
, R6 E+ Z% D' T0 Z9 D9 _8 l+ ^. ^! Z6 K. a
    for ( int i=0; i< 30; i++ )+ t! q! S( P0 Z
        flag = true;
1 @" ]5 |4 {: b6 |. K. U. Y7 ]2 P- a$ c+ F' Z
    int n = 30;//还剩几个人3 }6 G0 A( n% F) |
    int cnt;7 r5 H% A6 I# x8 M- c
    int pos = -1;//初始值不一定从0开始,设为-1处理起来较方便$ L: ?: Y/ H2 P9 Q0 E6 Y9 J
    while ( n > 0 )
# G( z2 G) a/ U, t! H# F/ c    {
9 ]3 n7 q2 @( R6 Z, e0 @        cnt = 0;
& {. T6 {0 z: S* f4 f+ e        while ( cnt < 5 )) w) K7 L" y( Z7 f+ y3 o) D% k% b
        {
& [# Q/ W, h8 W            if ( ++pos == 30 )
6 b' A' {1 f3 e0 @2 E. e1 k- b! c                pos = 0;
, Q3 d* I! N+ X8 J            if ( flag[pos] )//此人还没被毙掉
3 B  ~& o; a+ l# L5 V. P/ T' A  ~                cnt ++;
$ d' F# Z3 g$ l2 J        }# g# {) G; e' [& u1 @0 ~9 D. P# X
        //退出时cnt == 5,pos指向报5的人
: A7 t( B& d/ ]- z% I        flag[pos] = false;//毙掉
8 J0 j. e6 [4 J0 K2 P. w" M/ e        n --;//剩余人数减1& Q0 m" J8 \& ^& ?* ?5 n
    }9 K2 ]$ C- b8 x* ]
    //最后一个被毙的就是幸存者3 {: J6 w6 u- r& u. f6 u7 z
    //之所以加1是因为程序中从0开始计数,输出却以1开始计数
& E( s  B$ U1 Y% \9 q    cout << pos + 1 << ' ';
& Y# \' n; u  n# Z6 R9 P}1 J2 T8 H' r" c8 U7 d2 U
1 x& Y- C7 h6 U
3: 一个数被5除余3,被7除余2,求此数最小为几。4 F4 ~, o9 O0 n% s) w
" \( `) ^5 }5 e9 f! X* s  c
    筛选法不一定非要标记true/false,有时候也可以使用计数来进行筛选,这个问题就是一例。
  l/ h" @  I1 u2 u! m# b    首先,如果问题有解,则解必小于 5 * 7 = 35,只用在此范围内筛选即可。
2 |) Q5 ^) T, [7 a3 _/ P6 K- O    在程序处理上,如果一个数满足一个条件,就将计数值加1,最后计数值为3的即为所求。  [7 ^/ h. p; G/ j7 w7 i. U
- {/ E& a* X# |2 F( [; w
void fun3()
" e7 n1 D/ M4 V{
& p! q8 J# j, W& I! E2 j) E    int a[105];//105 = 5 * 7- A& `* \: `' F: M: K' f5 N
    int i;8 q" p" E# ?8 W
    //计数清0
5 {, E" X0 @. l' ]6 r- G6 `8 A1 N    for ( i = 0; i < 35; i++ )* Q" e" q! l7 z2 ?( j' P1 c
        a = 0;- o" @) ^+ y# y& y  A- m% ?" t$ W
    //开始筛选
8 Q; Q" _& \/ L4 n) |    for ( i = 3; i < 35; i += 5 )
4 C9 i3 {9 z' |; |        a ++;" y( o: v9 p" V
    for ( i = 2; i < 35; i += 7 )
, Q4 m& `* F5 G/ N- d        a ++;) ?( z% N6 Z) {! V

8 Q0 ?0 m$ _) F7 F6 l& s1 i. q    for ( i = 0; i < 35; i++ )
6 \8 k9 V% z- ]* }3 {* x' f2 L2 V        if ( a == 3 )% N% P' o1 z2 H, i3 c/ c! _
        {1 C& n4 X# Y& L' k5 j1 p
            cout << i << endl;
0 t* D" {9 w# h. k4 b  T            return;
; A1 O6 |/ j9 ]9 n        }
5 z3 P' j. i! E4 P6 p+ @    //如果执行到这里说明无解
6 N- ?& ]: t* O) c- f' Q7 y    cout << "No Answer!" << endl;3 o, _7 U4 k5 o5 ~6 N
}! p3 G5 A5 S) y8 L7 F2 c

' V8 B1 }* t' b6 g$ z
0 ~7 q; S* ]; l& e, G% T( m总结:
* U8 ^3 G; C& A    筛选法的时间效率较高,但需要一个辅助数组,这就意味着对规模很大的问题不适用。例如第3个问题,条件多1个,需要的空间就翻几倍。解决的办法是:
6 u& R& d3 \6 b0 I
( S, O' L1 O; y+ gfor ( int i = 0; i< n; i++ )
( W8 i* r1 Z. d8 C+ G{
5 U+ F6 T$ @; K  a    if ( i % 5 == 3 && i % 7 == 2 && ... )
0 v0 {0 t8 h; u4 }6 c        cout << i;
8 n2 h4 w& A1 p  ^4 E}; ?! x; E5 W8 A9 m+ H
    但相应的,这样做速度就慢了下来。所以还得根据问题的规模来决定使用什么方案。
  V; L3 D) @  g6 D) i$ u4 D2 i  W8 t# r. \0 u) k; w3 d/ e
    总体来讲,对于可以条件判断较复杂,且根据前一个(不)符合条件的情况较简单的推出下一个(不)符合条件的情况,(不)符合条件的情况分布较稀疏的问题,用筛选法速度较快。如果第3题中加一个条件被2除余1,用筛选法就不太合算了。/ g# L1 f4 J% H! S
1 U! q7 @* |% e/ Q1 n/ V/ i
    最后说明一下,此次给出的程序目的在于说明方法,在效率并不是最高的
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-7-17 19:23 , Processed in 0.614468 second(s), 58 queries .

回顶部