- 在线时间
- 0 小时
- 最后登录
- 2004-7-22
- 注册时间
- 2004-5-28
- 听众数
- 1
- 收听数
- 0
- 能力
- 0 分
- 体力
- 124 点
- 威望
- 0 点
- 阅读权限
- 20
- 积分
- 43
- 相册
- 0
- 日志
- 0
- 记录
- 0
- 帖子
- 4
- 主题
- 7
- 精华
- 0
- 分享
- 0
- 好友
- 0
升级   40% 该用户从未签到
 |
所谓筛选法就是从全集中将不合格的项全部删去,剩下的就是答案。% n' F2 [( Y6 V6 k7 I3 a
2 b& {* H" } l8 r4 G1: 求1-100之间的质数* h8 V" h1 F6 z0 _$ d
- f: S2 t0 V6 @ 原理:先将2的倍数全部划掉,再将3的倍数全部划掉……直到将10的倍数全部划掉(10^2 = 100 )。剩下的就是质数.
- I7 |; u u& s' P! }
K$ K# |) S9 ovoid fun1()8 T) f+ e2 R! n% p' \
{( A6 O& @3 I4 j+ w8 y, a
int i, j;
; P% J# S) I, N! P \9 y( ` bool flag[100];
& u$ r5 z, z4 t" v9 E. U+ u* `" R; i& J# Z
for ( i = 2; i < 100; i++ )' [' C1 a0 h3 s4 f7 z7 E5 v* d" v
flag = true;6 P X' [ i, |* c3 \
5 ~% d2 m- ~) w) `1 k" E5 X
//下面开始划掉合数
* _5 S' r6 K( E- [1 [& M- j2 Z for ( i = 2; i < 10; i++ ) //因为合数的最小正因数不大于它的平方根
8 O' Y# _! c* a9 R! @+ q7 b0 | {8 Y6 |$ m/ k0 F0 z3 n5 v
if ( flag == false ): y% h: O4 `6 r0 Z, t+ a5 J' k
continue; //既然i已经是合数,它的倍数应该已经被划掉 p2 b+ {& I7 k }
for ( j = 2; j * i < 100; j++ )//划掉i*j8 F2 J% U L3 b
flag[i*j] = false;: V$ L* T: b; {. j. V3 ?7 [/ Z9 w% m
}
( C& r. p# G$ l% m$ a8 y
# B2 g u. N$ Q- B; [& T //输出结果 ^+ j9 Z9 a+ @
for ( i = 2; i < 100; i++ )
7 Q, u$ {- H# t5 T$ p K) ^ if ( flag ); m! J1 m4 M4 Q
cout << i << ' ';9 s7 G- F6 i: [ j4 ~
}
7 }: S6 B I Z) P: j" W. _. \2 Q( ^" M7 Q
2: 30个人站成一圈,从第一个人开始报数,凡报到5的拉出去毙了,剩下的人接着从1开始报,直到只剩一人放掉。想活命该站哪?
! V9 ~) q! r( R. b& E# x- f# L8 b- s! t: V9 S3 P# k
这是个经典问题,解法就是模拟整个过程,有点类似于循环队列。
( r0 J% i5 s$ g# J* Z7 i- c$ ?- a5 Z8 }) p! ^/ t1 |- \, H
另外,为了程序上处理方便,可以假定所有的人都拉去毙了,然后看一下最后一个被毙掉的是谁。另一处为了处理方便而采取的措施是pos的初始值设为-1.很多时候,对问题的问法稍作变动,或者将初始值、加减变量的位置稍作调整,用程序处理起来会方便很多。
' n* w! ]6 ?% j: D9 C. h D Q, [/ L
$ c* c- w5 b( g/ M8 gvoid fun2(): N/ W1 n8 t+ S0 E: ]
{
Z4 g' S8 a5 j! j0 Z$ O& s+ W bool flag[30];//标记第i个人的状态,false已被毙掉,true还没被毙掉
; a) ?- N2 j \' d6 {
7 x& r+ L8 }; e+ y# y6 W8 [8 j for ( int i=0; i< 30; i++ )
" V# w; D E0 L9 z$ `+ X; y flag = true;
3 S- c+ A! g% T& z, H( k1 z" o
# ~- t! w* H7 I, `& W! { int n = 30;//还剩几个人
! V, w# E* K9 C6 K% g3 ~/ k5 d; Y& w+ [ int cnt;
! U6 A C: g, b int pos = -1;//初始值不一定从0开始,设为-1处理起来较方便
/ @7 o; B* C# o while ( n > 0 )
0 Q d$ D" S; V# ]! ~8 E {
4 F+ S5 L. d0 _8 t4 G, E7 z. T0 q; Q. E cnt = 0;
# ~6 }4 ?( v, H) a while ( cnt < 5 )) t5 {3 s/ C& R/ f
{
( f- e$ z5 Q% U! f if ( ++pos == 30 ). g0 E# O5 r* e& s
pos = 0;
" ^6 ?- C# p2 l a4 n if ( flag[pos] )//此人还没被毙掉
9 r2 ?$ a$ H# x- @8 h! I+ n1 A( @1 p cnt ++;7 b$ A3 B' t$ J8 z# X
}
}- w, M; h5 [1 j; m$ q" b/ e1 A //退出时cnt == 5,pos指向报5的人
. t4 X4 J8 D% L- t) t& O- V* Z E: t flag[pos] = false;//毙掉
) g5 k3 c! \4 h n --;//剩余人数减1: o T9 }8 L3 U, O+ {
}+ t8 V! m- B& k8 w7 f1 ^' Q
//最后一个被毙的就是幸存者
+ D- `# r" `% o //之所以加1是因为程序中从0开始计数,输出却以1开始计数' X3 m3 [0 `* l3 `. I# r
cout << pos + 1 << ' ';
2 D% ~1 L. h ]7 t5 m5 V}+ u% j/ K# P' ]5 r2 P# v6 Y$ _0 K
. L, B! O% ^- Q7 S' A, K w3: 一个数被5除余3,被7除余2,求此数最小为几。
: Z8 p9 u" o+ Q
5 B7 d0 b' |8 \ 筛选法不一定非要标记true/false,有时候也可以使用计数来进行筛选,这个问题就是一例。- a1 f7 L- e/ n4 Q! {1 c
首先,如果问题有解,则解必小于 5 * 7 = 35,只用在此范围内筛选即可。
" z8 q2 t' r9 o0 {( s 在程序处理上,如果一个数满足一个条件,就将计数值加1,最后计数值为3的即为所求。" p+ }+ v# H3 |$ n
* G! z) w: @& K1 e1 T
void fun3()7 ~) [) \5 z7 H5 r
{
6 J) |8 {, U; o8 o int a[105];//105 = 5 * 7
6 B& a/ n) X- U1 C2 G& ]0 N int i;) I% E7 a; @4 n7 @4 l) ~
//计数清0
# G4 q$ l& K" w1 f/ n; \ G for ( i = 0; i < 35; i++ )6 r8 f3 Z' h) Z; e; z3 \+ D
a = 0;3 Z3 }/ V0 a; M: V' ~: G2 b1 d
//开始筛选
- W9 j; O7 o5 p9 C" h8 J for ( i = 3; i < 35; i += 5 )
: ^3 i% q) J u( {4 A a ++;( Q" ~( @4 a+ E+ X$ A( F
for ( i = 2; i < 35; i += 7 )4 M" C6 e6 b D0 K0 l# ?, p
a ++;1 ]) U7 n' S" D
$ v5 d/ v7 ~# {# ]2 P3 i
for ( i = 0; i < 35; i++ )
% U) [" G: e3 ]7 R( A* B: P$ R" B if ( a == 3 )
r3 x) h- N$ r8 ~& y l. @ {
; g- n4 H4 D) z" e2 q) W( R/ g! c1 ~ cout << i << endl;
# u1 H: G8 O3 V5 R. _ return;
- h0 `8 s3 ~( M- U' l9 k }3 @, }$ k! d O# A1 V n
//如果执行到这里说明无解3 q- i2 h. v0 o% }- {" X, b
cout << "No Answer!" << endl;
. O; U, Z+ q, X& L# i/ P3 w}
' r7 g1 r d& N9 U
) k7 I, N% L# N% P
1 @9 U7 r# ?- I/ S/ [总结:
6 o$ t, Z% h6 [+ m4 _ 筛选法的时间效率较高,但需要一个辅助数组,这就意味着对规模很大的问题不适用。例如第3个问题,条件多1个,需要的空间就翻几倍。解决的办法是:. E/ F- c' ~0 ?
1 ~2 R6 ~ F6 m w
for ( int i = 0; i< n; i++ )
( _3 b5 v$ L. Y0 g/ e4 W{
% W- x: x$ [* I if ( i % 5 == 3 && i % 7 == 2 && ... )
2 j+ H7 ?3 D/ _+ M, y. V3 M cout << i;/ k' j! b- h4 G, M J
}8 H# J( e/ W! Y7 U! h6 M, \3 ?
但相应的,这样做速度就慢了下来。所以还得根据问题的规模来决定使用什么方案。3 J# d0 R- n* r, B8 E' R7 L
8 k) ]4 @0 ^3 I5 t
总体来讲,对于可以条件判断较复杂,且根据前一个(不)符合条件的情况较简单的推出下一个(不)符合条件的情况,(不)符合条件的情况分布较稀疏的问题,用筛选法速度较快。如果第3题中加一个条件被2除余1,用筛选法就不太合算了。$ Q3 O, N U# z! r5 w; p& g- r% t
: z* M8 ^/ R, ]; U% @$ r
最后说明一下,此次给出的程序目的在于说明方法,在效率并不是最高的 |
zan
|