- 在线时间
- 0 小时
- 最后登录
- 2004-7-22
- 注册时间
- 2004-5-28
- 听众数
- 1
- 收听数
- 0
- 能力
- 0 分
- 体力
- 124 点
- 威望
- 0 点
- 阅读权限
- 20
- 积分
- 43
- 相册
- 0
- 日志
- 0
- 记录
- 0
- 帖子
- 4
- 主题
- 7
- 精华
- 0
- 分享
- 0
- 好友
- 0
升级   40% 该用户从未签到
 |
所谓筛选法就是从全集中将不合格的项全部删去,剩下的就是答案。3 z+ b# S* ~4 w. n" q0 [: m0 B% {
* F3 a/ O; n7 V# j5 |- K
1: 求1-100之间的质数: v% A1 {4 h- \( A( N: c2 i% m
3 ]5 j$ h4 e" j0 G/ o
原理:先将2的倍数全部划掉,再将3的倍数全部划掉……直到将10的倍数全部划掉(10^2 = 100 )。剩下的就是质数.
; R" K' F; E L2 Q0 u
0 P3 q% X- H0 i- o- r! w% Kvoid fun1()
* L3 }$ N3 _# Z, G. p. ~9 ]{
3 F! |8 e7 D' j% X int i, j;
) ?5 L& j& S/ G: w5 n2 D bool flag[100];$ U6 ~1 b3 H' G1 V7 A- l' J, \
4 G4 G$ u$ @, q
for ( i = 2; i < 100; i++ ). V: w" b- \. ~! f
flag = true;
6 }7 }2 M, ^+ g9 `( z8 n! V' E7 [. h8 r( D3 V
//下面开始划掉合数& l9 b& K7 J: v O7 \% G! H7 H& z
for ( i = 2; i < 10; i++ ) //因为合数的最小正因数不大于它的平方根% l2 y- G2 E3 K# x1 S# A6 p0 g$ v
{
3 w/ D+ o) ^# |9 K1 |! l; A3 ~0 } if ( flag == false ) e, s0 }* A, z' a$ R5 L' `9 A
continue; //既然i已经是合数,它的倍数应该已经被划掉2 `9 d4 i. g; x6 g
for ( j = 2; j * i < 100; j++ )//划掉i*j4 c/ ]- ?6 U! N. H F6 S8 ?9 ]2 l
flag[i*j] = false;
2 v# r: M8 {7 Q) N- g }
o$ n. Y, }) {' K9 r: U+ q: i- S- @6 T* W' B
//输出结果
. T, X: T7 R# R- z: J7 r for ( i = 2; i < 100; i++ )# C* A: L7 l/ ?
if ( flag )
+ C" k5 n6 i- g5 R& X8 g0 T; P) Z cout << i << ' '; X+ c9 O( i0 |, d5 j" x1 V1 Z
}. a8 o. x# F3 c4 t
! G# \& a" C! Q& n/ }1 T
2: 30个人站成一圈,从第一个人开始报数,凡报到5的拉出去毙了,剩下的人接着从1开始报,直到只剩一人放掉。想活命该站哪?
4 T9 e9 l, [, P( I" W, E1 ? ^# i8 [" W9 |+ N9 F/ Z
这是个经典问题,解法就是模拟整个过程,有点类似于循环队列。
% q9 b, M6 p j- r1 h2 ?
7 ?, ^, o. z" D+ @" m" x2 z 另外,为了程序上处理方便,可以假定所有的人都拉去毙了,然后看一下最后一个被毙掉的是谁。另一处为了处理方便而采取的措施是pos的初始值设为-1.很多时候,对问题的问法稍作变动,或者将初始值、加减变量的位置稍作调整,用程序处理起来会方便很多。
; A$ x* P; w1 P/ \! d" @9 Q
- g# Q5 r( |( m2 zvoid fun2()2 @. y! l3 |" o7 u3 z& I2 j
{4 q' p5 ]7 Q+ I4 a2 O( k; U
bool flag[30];//标记第i个人的状态,false已被毙掉,true还没被毙掉
# z$ T3 X1 Z* {" `
( Y- |' D+ y; X" e for ( int i=0; i< 30; i++ )" T; E& Q- y! I, b9 A" O2 J
flag = true;
0 c6 x8 X' d) S6 x- t9 T* |
9 z& M7 Z& M; i* ^4 N int n = 30;//还剩几个人
4 J9 @$ X: F- ?9 S int cnt;( I( O! K: y# x: o5 t( m
int pos = -1;//初始值不一定从0开始,设为-1处理起来较方便% j- t! ?; K5 L: J, X% F3 \, M" _
while ( n > 0 )
, @3 J; R Q0 G {
5 X2 E4 x1 g4 X7 q$ O& N' B) s cnt = 0;
; f+ o0 M) ?2 j0 E while ( cnt < 5 )
. Z I. K. u+ d: d5 @7 N {
8 Y) e5 ]" {0 Z3 ?3 q9 Z; [ if ( ++pos == 30 )
0 v% |8 j7 z1 c, Z0 F% E0 O% | pos = 0;
. j- C4 T, q2 B6 C* I if ( flag[pos] )//此人还没被毙掉5 o' `" J4 e7 S" l5 |( o. Y
cnt ++;9 ?3 M+ @6 i a T, R/ b
}
, T0 U& w1 Q9 x6 p: w; h+ l //退出时cnt == 5,pos指向报5的人
/ p+ q, I/ x& C flag[pos] = false;//毙掉4 C7 H1 C& S4 C* j; _ f- k9 [
n --;//剩余人数减12 ~0 Q# x7 W+ Z# d; C
}
1 j7 W0 h. z( g' \/ \% u //最后一个被毙的就是幸存者' H) I. z d! U, U) U) H0 ~1 n5 E" _
//之所以加1是因为程序中从0开始计数,输出却以1开始计数' i$ r* f/ u4 \2 P* Z2 |5 S, ^
cout << pos + 1 << ' ';
8 E9 @, v0 z& [7 a J& Q}
4 b; A! }, Y7 g: V
& F0 n6 ?8 D2 ]3: 一个数被5除余3,被7除余2,求此数最小为几。
8 D- Q8 V0 l* J$ d; I" y* n
# b+ I* N/ P9 \, Q0 | 筛选法不一定非要标记true/false,有时候也可以使用计数来进行筛选,这个问题就是一例。0 r) u$ g! x. u7 r3 B8 z; I
首先,如果问题有解,则解必小于 5 * 7 = 35,只用在此范围内筛选即可。) p5 E! c$ {3 {: @
在程序处理上,如果一个数满足一个条件,就将计数值加1,最后计数值为3的即为所求。
& h( Y- X; R; ~+ d; f v2 Q4 h h7 n3 R* Z1 a N- d+ q
void fun3()
! L7 b0 M( r, R0 S, ~{
& o: f3 V& X* |3 O int a[105];//105 = 5 * 7
) M) ^! D- O% _1 j" g int i;
+ P# \3 l; Q/ b. T* ` //计数清0( g0 u/ r1 Y$ i+ g' _
for ( i = 0; i < 35; i++ )
) r% O; ]/ o# H# P4 Y$ r8 | a = 0;
' ?/ a$ r b5 X- T //开始筛选' ^0 O# _, g: G* o1 e+ [
for ( i = 3; i < 35; i += 5 )& j0 T9 B6 N; W1 z; t
a ++; D: v4 G; S5 q8 M5 r5 z1 e; d7 |" n
for ( i = 2; i < 35; i += 7 )
C1 Z" E" q- c" {3 Z' G a ++;
$ f$ f, |6 }; H0 w; k2 ^- Y% A6 |, T: J! h/ B8 p8 O; N
for ( i = 0; i < 35; i++ )1 F) `7 l; k5 I- ?% i ^
if ( a == 3 )) H, `4 h) C1 q5 R9 d# S
{
& ~, v" }6 t0 f cout << i << endl;
& C! ~3 X1 m% b! {4 o return;' v+ ^# J. j1 l, h; Z& `( P
}! L$ `& b+ }% M8 f6 V1 z9 `. c
//如果执行到这里说明无解
& E4 \/ J, a# j/ z5 ` cout << "No Answer!" << endl;
/ M0 u# y& N, \# b) v) c' I% _}
& e4 Q- x/ W, R" I3 i0 V+ e K4 f
( c* j, Y1 s0 `' L! h
( e7 z ? R, X* c总结:
; d% q" w9 m) Y6 p' ]5 \9 N 筛选法的时间效率较高,但需要一个辅助数组,这就意味着对规模很大的问题不适用。例如第3个问题,条件多1个,需要的空间就翻几倍。解决的办法是:4 \8 h; N, c, a5 ]2 D5 }" j
3 D- S( k+ v1 k1 }; m" }: Y
for ( int i = 0; i< n; i++ )+ H+ s" E1 c# H9 s3 e% B
{) B" l# V+ e" s" o* K1 b
if ( i % 5 == 3 && i % 7 == 2 && ... )
; U. u& {" M2 \- ^3 ^+ o cout << i;$ }; t" ^. \' T4 _$ u% @
}! Z' c8 H8 t: T- l* r
但相应的,这样做速度就慢了下来。所以还得根据问题的规模来决定使用什么方案。
0 d2 ~0 W" M2 Q! @/ ]9 ?' c8 Q* J6 b5 K" ^8 r; L/ Y6 a- T
总体来讲,对于可以条件判断较复杂,且根据前一个(不)符合条件的情况较简单的推出下一个(不)符合条件的情况,(不)符合条件的情况分布较稀疏的问题,用筛选法速度较快。如果第3题中加一个条件被2除余1,用筛选法就不太合算了。3 i8 x1 t/ Q. r
6 _( d) t' U* z; D. P 最后说明一下,此次给出的程序目的在于说明方法,在效率并不是最高的 |
zan
|