切换到宽版
  • 16317阅读
  • 11回复

算法初步 [复制链接]

上一主题 下一主题
离线gelanjie
 
只看楼主 倒序阅读 0 发表于: 2005-10-31
第一章 算法初步

第一节 程序设计与算法

 

一、算法
  算法是解决问题方法的精确描述,但是并不是所有问题都有算法,有些问题经研究可行,则相应有算法,但这并不是说问题就有结果。上述的“可行”,是指对算法的研究。
  1.待解问题的描述
  待解问题表述应精确、简练、清楚,使用形式化模型刻划问题是最恰当的。例如,使用数学模型刻划问题是最简明、严格的,一旦问题形式化了,就可依据相应严格的模型对问题求解。
  2.算法设计
  算法设计的任务是对各类具体问题设计良好的算法及研究设计算法的规律和方法。常用的算法有:穷举搜索法、递归法、回溯法、贪心法、分治法等。
  3.算法分析
  算法分析的任务是对设计出的每一个具体的算法,利用数学工具,讨论各种复杂度,以探讨某种具体算法适用于哪类问题,或某类问题宜采用哪种算法。
  算法的复杂度分时间复杂度和空间复杂度。
  .时间复杂度:在运行算法时所耗费的时间为f(n)(即 n的函数)。
  .空间复杂度:实现算法所占用的空间为g(n)(也为n的函数)。
  称O(f(n))和O(g(n))为该算法的复杂度。

  二、程序设计
  1.程序
  程序是对所要解决的问题的各个对象和处理规则的描述,或者说是数据结构和算法的描述,因此有人说,数据结构+算法=程序。
  2.程序设计
  程序设计就是设计、编制和调试程序的过程。
  3.结构化程序设计
  结构化程序设计是利用逐步求精的方法,按一套程式化的设计准则进行程序的设计。由这种方法产生的程序是结构良好的。所谓“结构良好”是指:
  (1)易于保证和验证其正确性;
  (2)易于阅读、易于理解和易于维护。
  按照这种方法或准则设计出来的程序称为结构化的程序。
  “逐步求精”是对一个复杂问题,不是一步就编成一个可执行的程序,而是分步进行。
  .第一步编出的程序最为抽象;
  .第二步编出的程序是把第一步所编的程序(如过程、函数等)细化,较为抽象;
  .……
  .第i步编出的程序比第i-1步抽象级要低;
  .……
  .直到最后,第n步编出的程序即为可执行的程序。
  所谓“抽象程序”是指程序所描述的解决问题的处理规则,是由那些“做什么”操作组成,而不涉及这些操作“怎样做”以及解决问题的对象具有什么结构,不涉及构造的每个局部细节。
  这一方法原理就是:对一个问题(或任务),程序人员应立足于全局,考虑如何解决这一问题的总体关系,而不涉及每局部细节。在确保全局的正确性之后,再分别对每一局部进行考虑,每个局部又将是一个问题或任务,因而这一方法是自顶而下的,同时也是逐步求精的。采用逐步求精的优点是:
  (1)便于构造程序。由这种方法产生的程序,其结构清晰、易读、易写、易理解、易调试、易维护;
  (2)适用于大任务、多人员设计,也便于软件管理。
  逐步求精方法有多种具体做法,例如流程图方法、基于过程或函数的方法。
  [例]求两自然数,其和是667,最小公倍数与最大公约数之比是120:1(例如(115,552) 、(232,435))。
  [解]两个自然数分别为m和667-m(2≤m≤ 333)。
  处理对象:m(自然数)、l(两数的最小公倍数)、g(两数的最大公约数)。
  处理步骤:对m从2到333检查l与g的商为120,且余数为0时,打印m与667-m 。
  第一层抽象程序:
  Program TwoNum;
  Var   m,l,g:integer;
  Begin for m:=2 to 333 do
    begin l:=lcm(m,667-m);   {求最小公倍数}
    g:=gcd(m,667-m);   {求最大公约数}
    if (l=g*120)and(l mod g=0) then
      writeln(m:5,667-m:5);
    end;
  End.
  第二层考虑函数lcm(最小公倍数)、gcd(最大公约数)的细化。
  最大公约数问题是对参数a、b,找到一个数i能整除a与b,i就是gcd的函数值。
    Function gcd(a,b:integer):integer;
    var i:integer;  
    begin for i:=a downto 1 do
    if not((a mod i=0)or(b mod i=0)) then gcd:=i;
    end;
  而最小公倍数的计算是:若干个b之和,若能被a整除,则该和便是a、b的最小公倍数。
    Function lcm(a,b:integer):integer;
    var i:integer;
    begin i:=b;
    while i mod a=0 do i:=i+b;
    lcm:=i;
    end;





--------------------------------------------------------------------------------

 第 1 楼  

第二节 编程入门题例

编程入门题(一)

1、位数对调:输入一个三位自然数,把这个数的百位与个位数对调,输出对
  调后的数。例如:Input 3 bit natrue data:234
            n=432
  [解]1.先确定输入数n是否三位数,即n>99且n<=999。
    2.位数对调:n=abc→cba=x          
      ①百位数a=n整除100;②十位数b=(n-a*100)整除10;③个位数c=n除以10的余数;
3.得对调后的数:x=c*100+b*10+a        
[程序]                          
{$I-} {输入的数据为整数}        
program Threebit;
var x,n,a,b,c:INTEGER;                
BEGIN write('Input 3 bit nature data:'); readln(n);                                  
IF (n>99) and (n<1000) then            
  begin a:=n DIV 100;   {求百位数}
    b:=(n-a*100) DIV 10;{求十位数}
    c:=n mod 10;     {求个位数}
    x:=c*100+b*10+a;   {得新数X}
    writeln('Number=',x:3);              
  end
ELSE writeln('Input error!');
END.                              
2、求三角形面积:给出三角形的三个边长为a,b,c,求三角形的面积。
  提示:根据海伦公式来计算三角形的面积:
      S= ;Area=
[解]1.输入的三角形三边长a,b,c要满足“任意两边长的和大于第三边长”。    
  2.按海伦公式计算:s=(a+b+c)/2;x=s*(s-a)*(s-b)*(s-c)
    这时若x>=0,则求面积:area= ,并输出area的值。
[程序]
PROGRAM hl;
VAR a,b,c,s,x,area:real;
BEGIN
write('Input a,b,c:');readln(a,b,c);
If (a>0) and (b>0) and (c>0) and (a+b>c)and(a+c>b)and(b+c>a) Then
  Begin s:=(a+b+c)/2; x:=s*(s-a)*(s-b)*(s-c);
    If x>=0 Then Begin Area:=SQRT(x);writeln('Area=',area:8:5); End;
  End
Else writeln('Input error!')
END.
3、模拟计算器:试编写一个根据用户键入的两个操作数和一个运算符,由计算机输出运算结果的程序。这里只考虑加(+)、减(-)、乘(*)、除(/)四种运算。
  例1:Input x,y:15 3
      Input operator(+,-,*,/):+
      15.00+ 3.00= 18.00
  例2:Input x,y:5 0
      Input operator(+,-,*,/):/
      divide is zero!
[解]该题关键是判断输入的两数是作何种运算(由输入的运算符operator决定, 如'+'、'-'、'*'、'/'分别表示加、减、乘、除法的运算)。其中要进行除(/)运算时,要先进行合法性检查,即除数不能为0。
[程序]
PROGRAM Oper;
Var x,y,n:real;
operator:char;
Begin
write('Input x,y:');readln(x,y);
write('Input operator:');readln(operator);
Case operator of
  '+':n:=x+y;     {加法运算}
  '-':n:=x-y;     {减法运算}
  '*':n:=x*y;     {乘法运算}
  '/':If y=0 then {除法运算}
      begin writeln('Divide is zero!');halt;end
    Else n:=x/y;
  else begin writeln('Input operator error!');halt;end;
End;
writeln(x:6:2,operator,y:6:2,'=',n:6:2);
End.


 

--------------------------------------------------------------------------------



4、念数字:编一个“念数字”的程序,它能让计算机完成以下工作:当你输入一个0至99之间的数后,计算机就会用汉字拼音印出这个数的念结束。
例1:Input data:35
    SAN SHI WU
  例2:Input data:0
      LING
  如果输入的数不在0到99之间,就印出“CUO LE”(错了),请求重新输入。
  注:为了使不熟悉汉语拼音的同学也能做这个题,把“零,一,二,三,……,九,十”的拼音法写在下面。
  零 LING   一 YI   二 ER   三 SAN   四 SHI   五 WU
  六 LIU   七 QI   八 BA   九 JIU   十 SHI
[解]输入数在0~99之间,若x为两位数则拆分为十位数、个位数。然后调用念
  数过程Readdigit用汉字拼音印出各位数(0~9)的念。
[程序]
{$I-}
Program NinShu;
Var x,a,b:Integer;
Procedure ReadDigit(n:Integer);{念数过程:n=0~9}
Begin
Case n of
  0:write('LING ');
  1:write('YI ');
  2:write('ER ');
  3:write('SAN ');
  4:write('SHI ');
  5:write('WU ');
  6:write('LIU ');
  7:write('QI ');
  8:write('BA ');
  9:write('JIU ');
End;
End; {ReadDigit}

Begin {main}
Repeat write('Input data:');readln(x);
  if (x<0) or (x>99) then writeln('Cuo Le');
Until (x>=0)and(x<=99);
If (x>=0)and(x<=9) then ReadDigit(x) {调用念数过程}
  Else Begin a:=x DIV 10; b:=x mod 10; {位数拆分}
    If a<>1 then ReadDigit(b);
    writeln(' Shi');
    if b<>0 then ReadDigit(b);
  End;
writeln;
End.
5、数列找数:数组A(N)的各下标变量中N个互不相等的数,键盘输入正整数M(M≤N),要求打印数组中第M大的下标变量的值。
  例如:数组A(10)的数据为:
A(1)   A(2)   A(3)   A(4)   A(5)   A(6)   A(7)   A(8)   A(9)   A(10)
16   57   20   19   38   41   6   13   25   32
运行结果:INPUT AN NUMBER:3
        A(5)=38       (即第3大的数是A(5)=38)
  [解]该题要从N个互不相等的数中找第M大的值。有以下两种解法:

解法一:初始时:A数组存放N个互不相等的数;B数组用于存放数组A的下标。见下表一。
下标值i   1   2     3   4     5   6   7   8   9   10
数组A   16   57   20   19   38   41   6   13   25   32
数组B   1   2     3   4     5   6   7   8   9   10
      降序处理(冒泡排序法):
      数组A的元素由大到小进行排序,同时数组B的元素排列也随之变化。
下标值I   1   2     3   4     5   6   7   8   9   10
数组A   57   41   38   32   25   20   19   16   13     6
数组B(原数组A的下标)     2     6   5   10   9   3   4   1     8     7
例题中M=3,由表二知A[3]=38,B[3]=B[M]=5(原数组A的下标值)即为所求。
[程序]
Program Max01;{冒泡排序法}
var i,j,n,m,x:integer;
  A,B:ARRAY[1..100] of integer;

Procedure Init; {读数初始化过程}
Var i,j:integer; fd:boolean;
Begin
write('Input N:');readln(N); {读入N}
if N<1 then begin writeln('Input error!');halt;end;
write('Input ',N:3,' Data:');
For i:=1 to n Do
  begin read(A);B:=i;end;{读入A,且B初值置为i}
Readln;
i:=1; fd:=false; {数组中的数有相同的标志}
while NOT fd and (i<=N-1) do
  Begin j:=i+1;
    While NOT fd and (j<=N) do
    begin fd:=A=A[j];   {若A=A[j],则fd=true;否则fd=false}
      j:=j+1;
    end;
    i:=i+1;
  End;
If fd then {fd为True,则表示数组中至少有两个相等的数}
  begin writeln('More equal number!');halt;end;
write('Input M:');readln(M);
If M>N then {表明所找的数M已超过输入数的总数N}
  begin writeln('Input error!');halt;end;
End; {Init}

Begin {MAIN}
Init;{ 读数过程 }
for i:=1 to N-1 do {冒泡排序}
  for j:=i+1 to N do
    if A<A[j] then
    begin x:=A;A:=A[j];A[j]:=x; {交换A与A[j]的值}
      x:=B;B:=B[j];B[j]:=x;   {交换B与B[j]的值}
    end;
writeln('A(',B[M],')=',A[M]); {输出第M大的数、原下标值}
End.


  解法二(搜索法):用B表示在A[1]、A[2]、A[3]、……、A[N]中比A大的个数(i=1,2,3,……,N)。搜索的结果见下表三:
下标值i   1   2     3   4     5   6   7   8   9   10
A数组   16   57   20   19   38   41   6   13   25   32
B数组   8   1   6     7   3   2   10   9   5   4
例题中M=3,由表三知B[5]=3=M,A[5]=38即为所求。
[程序]
Var i,j,k,m,n:integer;
A,B:ARRAY[1..100] of integer;

Procedure Init;
{具体程序见解法一}
Begin {MAIN}
Init; {读数过程}
for i:=1 to n do
  begin B:=1; {B初始值为1,即假定所有A都可能为最大数}
    for j:=1 to n do
    if (i<>j) and (A<A[j]) then B:=B+1;
    if B=M then k:=i;
  end;
writeln('A(',k,')=',A[k]);
End.


 









--------------------------------------------------------------------------------

 

在上述表三中,我们可以发现:例中M=3,在搜索过程中当下标i=5时,B[5]=M=3,此时已找到所求,即A[5]=38。这样i>5时就不用再搜索下去。因此,可对解法二的算法优化如下:
1.   读数至A数组
2.   i=1;fd=false; {fd:判断是否已找到所求数的标志}
3.当 (fd=false)and(I<=n) 时,做
  (1)B=1 {表示数列中比A小的数的总个数+1,初始值为1}
  (2)j=1
  (3)当j<=n时,做
    ①如果(i<>j)and(A<A[j]),则B的值加1。
    ②j=j+1
  (4)如果B=M,则输出所求:A,且fd=true。
  (5)i=i+1
4.程序结束。

[主程序]
Begin {MAIN}
Init;{读数过程}
i:=1;fd:=false;{找到所求解的标志值}
while not fd and (i<=N) do
  begin B:=1; {B初始值为1,即假定所有的A都可能为最大的数}
j:=1;
while j<=n do
    begin
      if (i<>j)and(A<A[j]) then B:=B+1;
      j:=j+1;
    end; {while j}
    if B=M then {找到所求便输出,并退出比较}
    begin writeln('A(',i,')=',A);fd:=true; end;
    i:=i+1;
  end;{while i}
End.

6、数制转换:编程输入十进制N(N:-32767~32767),请输出它对应的二
  进制、八进制、十六进制数。例如:
  INPUT N(-32767~32767):222
  222 TURN INTO 2:11011110
  222 TURN INTO 8:336
  222 TURN INTO 16:DE

[解]十进制数转化为某进制数的转换方法,如下图示:

              除x逆序取余法
        十进制数           x进制数(x=2,8,16等)

  例中n=222(十进制数),转换成x进制数的过程如下图示:

(1)十进制数→二进制数   (2)十进制数→八进制数 (3)十进制数→十六进制数
x=2 222 被除数(最大商)     x=8 222   6     x=16 222   E … (14)10
  2 111   0     低位       8   27   3       16   13   D … (13)10
  2   50   1       逆       8   3   3           0
  2   25   0   余   序           0        
  2   12   0   数   取
  2   6   0       余
  2   3   1       数
  2   1   1     高位
    0 (最大商为0时停止)
  将每次所得的余数由下至上排列(逆序取余数),即有:
  (222)10 转换成二进制数得到:1100010
  (222)10 转换成八进制数得到:336
  (222)10 转换成十六进制数得到:13、14
  这时得到的逆序余数串(在数组B[1]、B[2]、……、B[k]中)的每位数均为十进制数。程序中利用字符串A来计算x进制数的位数(即COPY(A,B+1,1)),见下表:
数组B     0   1   2   3   4   5   6   7   8     9   10   11   12   13   14   15
字串A     0   1   2   3   4   5   6     7     8     9     A     B     C     D     E     F
下标i   1   2   3   4   5   6   7   8   9   10   11   12   13   14   15   16
由上表得:(222)10=(1100010)2=(336)8=(DE)16
[程序]
{$I-}
Program jj;
var N,k:integer;
B:array[1..1000] of integer;

Procedure chg10(N,x:integer); {将十进制数N转换成x进制数}
Begin k:=0;   {转换后的x进制数位的长度}
while N<>0 do {N不为0时}
  begin B[k]:=N mod x; {除以x取余数}
    N:=N Div x;     {取最大商N}
    k:=k+1;         {x进制数位加1}
  end;
end;{chg10}

Procedure Sput(N,x:integer);{进制数输出}
VAR i:integer; A:string;
Begin A:='0123456789ABCDEF'; {表示x进制数的位数串}
write(N:6,' Turn into ',x:2,':');
for i:=k-1 downto 0 do write(copy(A,B+1,1));{逆序输出x进制数}
writeln;
end; {Sput}
begin {MAIN}
write('Input N(-32767 to 32767):');readln(N);
if (N<=-32767)or(N>32767) then
  begin writeln('Input error!');halt;end;
chg10(N,2);Sput(N,2);   {十进制数转换成2进制数,并输出}
chg10(N,8);Sput(N,8);   {十进制数转换成8进制数,并输出}
chg10(N,16);Sput(N,16); {十进制数转换成16进制数,并输出}
end.
1条评分
stevenjl 威望 +5 - 2005-10-31
离线gelanjie
只看该作者 1 发表于: 2005-10-31
编程入门题(二)

1、求素数:求2至N(2≤N≤500)之间的素数。例如:
输入:N=100
输出: 2   3   5   7 11 13
    17 19   23 29 31 37
    41 43   47 53 59 61
    71 73   79 83 89 97
    total=24   {表示2至100之间的素数有24个}
[解法一]素数是指除1及本身以外不能被其他数整除的自然数。下面介绍用穷举法求素数。
1.   2是素数;t=0;
2.   I=2~n,则:
(1)如果i是素数,则其必须是奇数且不能被2~√i 中的任一个数整除。
  (2)如果I是素数,则输出该素数且计数器t=t+1;
  3.输出2~N之间素数的总数:total=t;
4.程序结束

[程序]
program exa;
uses crt;
var i,k,n,w,t:integer;
  yes:boolean;
Begin t:=0;clrscr;write(‘N=’);readln(n);
if (n<2)and(n>500) then
  begin writeln(‘input error!’);halt;end;
write(2:5);t:=1;
for i:=2 to n do
  if odd(i) then
    begin yes:=true;
    w:=trunc(sqrt(I));k:=2;
    while (k<=w)and yes do
      begin if i mod k=0 then yes:=false; k:=k+1;end;
    if yes then begin write(i:5);t:=t+1; end;
    end;
writeln(‘total=’,t);
end.

[解法二]筛法求素数:
  1.建立一个包括2,3,…,N的数据“集合”R;
  2.顺序取R中的数(从素数2开始),同时将其及能整除它的数从R中划去。“筛法求素数”的过程如下图示:
素数R[1]             数据集合R
  2   { 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,……}
  3   {   3,   5,     7,   9,   11,   ……}
  5   {         5,     7,         11,   ……}
……               ………
  这样便可得到所求的素数:2,3,5,……。
[程序]
program Sushu;
var i,j,k,n,w,t:integer;
R,P:array [1..500] of integer;
Begin
write('N=');readln(n);
if (n<2) or (n>500) thenbegin writeln('Input N error!');halt end;
for i:=2 to n do R[i-1]:=i; writeln('Result:');t:=0;k:=n-1;
while k>0 do
  begin P:=R; {数组P保存在P中}
    write(R[1]:5); {输出素数} t:=t+1;w:=R[1];j:=0;
    for i:=1 to k do
    if P mod w<>0 then {划去w及 W的倍数}
      begin j:=j+1; R[j]:=P;end; {重新构造集合R}
    k:=j; {新建后R的元素个数}
  end; writeln;writeln('Total=',t);
end.

(f2);
  end.


 





 


--------------------------------------------------------------------------------



2、矩阵相乘:已知N×M1矩阵A和M1×M矩阵B(1≤M、M1、N≤10),求矩阵C(=A×B)。例如:
输入:N,M1,M=4 3 4
    A= 1   2   3        
3   4   5         提示:所谓矩阵相乘(如A×B=C),是指
4   5   6           Cij= ∑(Aik×Bkj)(i=1~N,j=1~M1,k=1~M)
5   –1 –2            
      B= 1   6   4   2     例如:
        2   3   4   1         C11=A11×B11+A12×B21+A13×B31
        –1   5   7   –3         =1×1+2×2+3×(– 1)
输出:C= 2   27   33   –5         =2
        6   55   63   –5         C42= A41×B12+A42×B22+A43×B32
        8   69   78   –5         =5×6+(–1)×3+(–2)×5
      5   17   2   15           =17
[解]该题主要考查矩阵的表示及其运算。矩阵A(N×M1)与矩阵B(M1×M)相乘得矩阵C(N×M),其解法如下:
    i=1~N,重复做
      j=1~M,重复做
  (1)cij=0; (2)k=1~M1,重复做Cij=Cij+Aik*Bkj; (3)输出Cij
[程序]
program JiZheng;
var i,j,k,N,M1,M:integer;
A,B,C:array [1..10,1..10] of integer;
Begin
write('N,M1,M=');readln(N,M1,M);
if (N>=1)and(N<=10)and(M1>=1)and(M1<=10)and(M>=1)and(M<=10) then
begin {输入N×M1矩阵A}write('A=');
for i:=1 to N do for j:=1 to M1 do read(A[i,j]);readln;
  {输入M1×M矩阵B} write('B=');
for i:=1 to M1 do for j:=1 to M do read(B[i,j]);readln;
  write('C=');
    for i:=1 to N do
    begin for j:=1 to M do{计算Cij= ∑(Aik×Bkj)}
      begin C[i,j]:=0; for k:=1 to M1 do C[i,j]:=C[i,j]+A[i,k]*B[k,j];
        write(C[i,j]:5); {输出矩阵Cij}
      end;
      writeln;write(' ':2);
    end;
    writeln;
  end
else writeln('Input N,M1,M error!');
end.

3、找数字对:输入N(2≤N≤100)个数字(在0与9之间),然后统计出这组数中相邻两数字组成的链环数字对出现的次数。例如:
输入:N=20 {表示要输入数的数目}
    0 1 5 9 8 7 2 2 2 3 2 7 8 7 8 7 9 6 5 9  
输出:(7,8)=2 (8,7)=3 {指(7,8)、(8,7)数字对出现次数分别为2次、3次)
  (7,2)=1 (2,7)=1
  (2,2)=2
  (2,3)=1 (3,2)=1
[解]该题主要是数组的存储表示及运用。数组A存放所输入的N个数,用数组B表示A与A[i+1]相邻数字对出现的次数。计算过程见下表:
数组A次数i   0 1 5   9 8   7   2   2   2   3 2   7   8   7   8   7   9   6 5   9 1 2   3 4   5   6   7   8   9 10 11 12 13 14 15 16 17 18 19
求链环数字的过程   I= 1: B[0,1]=1     I=2:B[1,5]=1     I=3: B[5,9]=1   I=4: B[9,8]=1 I= 5: B[8,7]=1     I=6:B[7,2]=1     I=7: B[2,2]=1   I=8: B[2,2]=2 I=9: B[3,2]=1     I=10:B[2,3]=1   I=11:B[2,7]=1     I=12:B[7,8]=1   I=13:B[8,7]=2     I=14:B[7,8]=2   I=15:B[8,7]=3     I=16:B[7,9]=1   I=17:B[9,6]=1     I=18:B[6,5]=1   I=19:B[5,9]=1
[程序]
Program Getdouble;
var i,N:integer; fd:boolean;
A:array[1..100] of integer;
B:array[0..9,0..9] of integer;
Begin fillchar(B,sizeof(B),0);{数组B初值置为0} write('N=');readln(N);
if (N>1)and(N<=100) then
  begin write('Enter ',N,' numbers:');
    for i:=1 to N do
    begin read(A); {输入A}
      if (A<0)or(A>9) then   {A的值在0与9之间}
        begin writeln('Input error!');halt;end;
    end;
    for i:=1 to N-1 do
    B[A,A[i+1]]:=B[A,A[i+1]]+1;{相邻数字对BA,A[i+1]值加1}
    fd:=true;writeln('Result:');
    for i:=1 to N-1 do
    if (B[A,A[i+1]]>0)and(B[A[i+1],A]>0) then
      begin write('(',A,',',A[i+1],')=',B[A,A[i+1]],' ');
        if A[i+1]=A then writeln {相邻数字相同,如(2,2)}
        else writeln('(',A[i+1],',',A,')=',B[A[i+1],A]);
        B[A[i+1],A]:=0;
        fd:=false;
      end;
    if fd then writeln('Not found!');
  end
else writeln('Input N error!');
end.











--------------------------------------------------------------------------------



4、蛇形矩阵:生成一个按蛇形方式排列自然数1,2,3,4,5,……,N2的 (1<N≤10)阶方阵。例如:
输入:N=4                 N=7
输出:1   3   4   10           1   3   4   10   11   21   22
      2   5   9   11           2   5   9   12   20   23   34
      6   8   12   15           6   8   13   19   24   33   35
      7   13 14   16           7   14   18   25   32   36   43
                          15   17   26   31   37   42   44
                          16   27   30   38   41   45   48
                          28   29   39   40   46   47   49
[解]本题考查重点是矩阵的表示及
  上下标运算,旨在培养观察和
  分析思维能力。
    例如,当N=7 时,把1,
  2,3,……,49逐一填入数组
  A中,搜索填数的方向如右图示:

  从图中,我们可以看出:对每个数字m(1,2,……,~N*N)来说,可能按以下四种搜索方向之一填数:
                    d=2(右上)
 
              m     d=3(向右)
      d=4    
      (左下)     d=1(向下)
  按照图10-1的搜索方向填数时,先要把当前数字m填入数组A[i,j]中,接下来就是要确定下一次的填数的坐标及其搜索方向(即d=?)。现分析如下:
  第一种情形(d=1,如m=2,7,15;35,44):
        (i,j)
        d=1     d=2(当j=1)
        (i+1,j)
         
          d=4(当j=N)
  第二种情形(d=2,如m=2,10,21;或34,43,48;或7,8,9,16,17,18,19等):
            d=2(当i<>1且j<>N)
         
        (i-1,j)   d=3(当i=1)
         
      d=2     d=1(当j=N)
      (i,j)
  第三种情形(d=3,如m=29,40,47;或4,11,22):
            d=3       d=2(当i=N)
        (i,j)   (i,j+1)
         
              d=4(当j=N)
  第四种情形(d=4,如m=28,39,46;或6,15;或5,12,13,14等):
              (i,j)
              d=4
        (i+1,j)   d=3(当i=1)
         
          d=4(当i=N且j<>1)

[程序]
Program she;
const max=10;
var d,i,j,m,N:integer;
A:array [1..10,1..10] of integer;

begin
write('N=');readln(N);
if (N>=1) and (N<=max) then
  begin i:=1;j:=1;m:=1;d:=1;
    repeat A[i,j]:=m;   {填数}
    case d of
      1: {第一种情形}begin i:=i+1; if j=1 then d:=2 else d:=4; end;
      2: {第二种情形}begin i:=i-1;j:=j+1;
if j=N then d:=1 else if i=1 then d:=3;end;
      3: {第三种情形}begin j:=j+1; if i=N then d:=2 else d:=4;end;
      4: {第三种情形}begin i:=i+1;j:=j-1;
if i=N then d:=3 else if j=1 then d:=1;end;
    end;
    m:=m+1;
    until m>N*N;
    writeln('OUTPUT:');
    for i:=1 to N do begin for j:=1 to N do write(A[i,j]:4); {输出填数} writeln;end;
  end
else writeln('Input N error!');
end.



 

--------------------------------------------------------------------------------



念数字那道题用字符串来实现应该会简单些吧
离线118140194
只看该作者 2 发表于: 2005-10-31
可以顶
离线tangyouze
只看该作者 3 发表于: 2005-11-04
" 零 LING   一 YI   二 ER   三 SAN   四 SHI   五 WU
六 LIU   七 QI   八 BA   九 JIU   十 SHI"


打错了,,“四”
  应该是 SI
离线fstarx
只看该作者 4 发表于: 2005-11-08
我是初学者
这个对我太有用了
离线youling
只看该作者 5 发表于: 2005-11-27
太好了顶!!!!!
离线二战小兵
只看该作者 6 发表于: 2007-11-14
ding
离线zcy691888
只看该作者 7 发表于: 2008-04-13
ding
离线wt061236
只看该作者 8 发表于: 2008-04-13
狂顶
离线hanhao
只看该作者 9 发表于: 2008-05-15
不错,谢谢,我是新手,正好需要
快速回复
限100 字节
 
上一个 下一个