【4.76】参考答案:
#include "stdio.h"
int a[20],b[20];
main()
{ int t=0,*m,*n,*k,*j,z,i=0;
printf("Input number 1:");
do
{ a[++t]=getchar()-'0';
}while(a[t]!=-38);
printf("Input number 2:");
do
{ b[++i]=getchar()-'0';
}while(b[i]!=-38);
if(t>i)
{ m=a+t;n=b+i;j=a;k=b;z=i;
}
else
{ m=b+i;n=a+t;j=b;k=a;z=t;
}
while(m!=j)
{ (*(--n-1))+=(*(--m)+*n)/10;
*m=(*m+*n)%10;
if(n==k+1 && *k!=1 ) break;
if(n==k+1 && *k)
{ n+=19;*(n-1)=1;
}
if(n>k+z && *(n-1)!=1) break;
}
while(*(j++)!=-38) printf("%d",*(j-1));
printf("\n");
}
【4.77】参考答案:
#include "stdio.h"
int a[20],b[20],c[40];
main()
{ int t=0,*m,*n,*k,f,e=0,*j,i=0;
printf("Input number 1:");
do
{ a[++t]=getchar()-'0';
}while(a[t]!=-38);
printf("Input number 2:");
do
{ b[++i]=getchar()-'0';
}while(b[i]!=-38);
j=c;
for(m=a+t-1;m>=a+1;m--,e++)
{ j=c+e;
for(n=b+i-1;n>=b+1;n--)
{ f=*j+*m * *n;
*(j++)=f%10;
*j+=f/10;
}
}
while(j>=c) printf("%d",*(j--)) ;
printf("\n");
}
【4.78】这是一个使用数组解决较复杂问题的典型题目。
棋盘如左图所示,图中箭头表示一个棋子从[1、1]点跳到[2、3]点。为了下面叙述的方便,将I、J表示棋子起跳点的行、列号,X、Y表示落子点的行、列号。
首先我们讨论如何从起跳点坐标求出可能的落子点的坐标。
从某点起跳,棋子最多可能有八个落子点,例如从I=3、J=5点起跳,八个可能的落子点的坐标是[4、5]、[5、4]、[5、2]、[4、1]、[2、1]、[1、2]、[1、4]、[2、5]。将起落点的行列坐标分开考虑,则由起点的行坐标分别与下列八个数相加,就可得到可能的八个落子点的行坐标:1、2、2、1、-1、-2、-2、-1,将这八个数存入数组b,即:
b[]={1,2,2,1,-1,-2,-2,-1},
落子点的行坐标X和起跳点行坐标有如下关系:
X=b[k]+I 1≤k≤8
如果由上式计算得到的落子点X的坐标值小于0或大于8,则表示落在了棋盘之外,应予舍弃。
同理得到起落点之间的列坐标关系数组是:
d[]={2,1,-1,-2,-2,-1,1,2}。
我们再讨论落子点的度数问题。对于棋盘中的某一点来说,周围最多有8个方向的棋子在这个点落子,把可能的落子数称为度数,棋盘上各点的度数如下图所示。
根据题意,一个点只能落子一次,所以落过子的点的度数应记为0,可跳向度数为0点的度数相应要减1。
根据上述数组,从一个起跳点出发,可能求出数个可以落子点的坐标,跳棋时到底确定落在这些点中的哪一个呢?我们确定一个原则是落在度数最少的点。如果可能落子点中有两个点的度数一样且都为是度数最少时,取后求出的点为落子点。因此,如果改变数组b、d中数的存放顺序,遇到两个度数最少点的先后顺序就要改变,整个跳棋路径就可改变。 2 3 4 4 4 4 3 2
3 4 6 6 6 6 4 3
4 6 8 8 8 8 6 4
4 6 8 8 8 8 6 4
4 6 8 8 8 8 6 4
4 6 8 8 8 8 6 4
3 4 6 6 6 6 4 3
2 3 4 4 4 4 3 2
在下面的程序中,将起落子行列关系的两个一维数组合并为一个二维数组,为了提高程序的可读性,不使用下标为0的数组元素。
参考程序:
int base[9][3]={0, 0, 0, /* 从起跳点求落脚点的基础系数数组 */
0, 1, 2,
0, 2, 1,
0, 2,-1,
0, 1,-2,
0,-1,-2,
0,-2,-1,
0,-2, 1,
0,-1, 2 };
main()
{ int a[9][9],object[9][9];
int i,j,k,p,x,y,m,n,cont;
int min,rm1,rm2,rm0=1;
for(cont=1;cont>0;)
{ for(i=0;i<=8;i++) /* 保存个点度数的数组 清零 */
for(j=0;j<=8;j++)
a[i][j]=0;
rm1=base[1][1]; /* 改变基础数组元素排列顺序 */
rm2=base[1][2];
base[1][1]=base[rm0][1];
base[1][2]=base[rm0][2];
base[rm0][1]= rm1;
base[rm0][2]= rm2;
for(i=1;i<=8;i++)
{ for(j=1;j<=8;j++) /* 计算各点度数存入数组a */
{ for(p=1;p<=8;p++)
{ x=i+base[p][1];
y=j+base[p][2];
if(x>=1&&x<=8&&y>=1&&y<=8)
a[x][y]++;
}
printf(" %d",a[i][j]); /* 输出度数表 */
}
printf("\n");
}
printf("Please Input start position:line,colume=?\n");
scanf("%d,%d",&i,&j); /* 输入起跳点坐标 */
for(k=1;k<=63;k++) /* 求棋盘上63个落步点 */
{ object[i][j]=k; /* 跳步路径存入数组object */
min=10;
for(p=1;p<=8;p++) /* 求从当前起跳点出发的8个可能落点 */
{ x=i+base[p][1];
y=j+base[p][2];
if(x>=1&&x<=8&&y>=1&&y<=8) /* 求出的可能落点在棋盘内 */
if(a[x][y]!=0) /* 此点没有落过棋子 */
{ a[x][y]--; /* 由于[i、j]点落过棋子,此点度数减1 */
if(min>a[x][y]) /* 判断当前可能点度数是否最小 */
{ min=a[x][y]; /* 保存可能最小度数点的度数 */
m=x; /* 保存可能最小度数点的坐标 */
n=y;
}
}
}
a[i][j]=0; /* 落过棋子的[i、j]点度数为零 */
i=m; /* 已求出的最小度数点为下次搜寻的起跳点 */
j=n;
}
object[i][j] = 64 ;
for(i=1;i<=8;++i) /* 输出跳步结果路径 */
{ for(j=1;j<=8;j++)
if(j==8) printf("%2d",object[i][j]);
else printf("%2d ",object[i][j]);
printf("\n");
if(i!=8) printf(" \n"); /* 每行输出8个数据 */
}
rm0%=8; /* 放在基础数组第一位的元素循环变化 */
rm0++; /* 基础数组下一元素放在第一位 */
printf("continue?(1 or 0)");
scanf("%d",&cont);
}
}
【4.79】分析:采用试探法求解。
如图所示,用I、J表示行、列坐标。
开始棋盘为空,对于第1个皇后先占用第一行即I=1,先试探它占用第一列J=1位置,则它所在的行、列和斜线方向都不可在放其它皇后了,用线将它们划掉。第2个皇后不能放在J=1、2的位置,试J=3。第2个皇后占用[2、3]后,它的行列和斜线方向也不可再放其它皇后。第3个皇后不能放在J=1、2、3、4的位置,试J=5。第4个皇后可以试位置[4、2],第5个皇后试位置[5、4]。第6个皇后已经没有可放的位置(棋盘上所有格子都已占满),说明前面所放位置不对。
退回到前一个皇后5,释放它原来占用的位置[5、4],改试空位置[5、8]。然后再前进到第6个皇后,此时仍无位置可放,退回到第5个皇后,它已没有其它位置可选择。进一步退回到第4个皇后释放位置[4、2]改试位置[4、7],再前进到第5个皇后进行试探,如此继续,直到所有8个皇后都选择一个合适的位置,即可打印一个方案。
然后从第8个皇后开始,改试其它空位置,若没有可改选的空位置,则退回到第7个皇后改试其它位置,若也没有空位置可改,继续退,直到有另外的空位置可选的皇后。将它原来占用的位置释放,改占其它新位置,然后前进到下一个皇后进行试探,直到所有8个皇后都找到合适位置,又求出一个解,打印输出新方案。按此方法可得到92个方案。
参考答案:
#define NUM 8
int a[NUM+1];
main()
{ int number,i,k,flag,nonfinish=1,count=0;
i=1;
a[1]=1;
while(nonfinish)
{ while(nonfinish && i<=NUM)
{ for(flag=1,k=1;flag && k
if(a[k]==a[i]) flag=0;
for(k=1;flag && k
if((a[i]==a[k]-(k-i)) || (a[i]==a[k]+(k-i))) flag=0;
if(! flag)
{ if(a[i]==a[i-1])
{ i--;
if(i>1 && a[i]==NUM) a[i]=1;
else if(i==1 && a[i]==NUM) nonfinish=0;
else a[i]++;
}
else if(a[i]==NUM) a[i]=1;
else a[i]++;
}
else if( ++i<=NUM )
if(a[i-1]==NUM) a[i]=1;
else a[i]=a[i-1]+1;
}
if(nonfinish)
{ printf("\n%2d:",++count);
for(k=1;k<=NUM;k++)
printf(" %d",a[k]);
if(a[NUM-1]
else a[NUM-1]=1;
i=NUM-1;
}
}
}
【4.80】参考答案:
double findy(float x)
{ if(x>=0 && x<2)
retuen(2.5-x);
else if(x>=2 && x<4)
return(2-1.5*(x-3)*(x-3)); else if(x>=4 && x<6)
return(x/2.0-1.5);
}
main()
{ float x;
printf("Please enter x:");
scanf("%f",&x);
if(x>=0 && x<6)
printf("f(x)=%f\n",findy(x));
else
printf("x is out!\n");
}
【4.81】注释:此程序采用模拟手工方式,对分数进行通分后比较分子的大小。
参考答案:
main( )
{ int i, j, k, l, m, n;
printf("Input two FENSHU :\n");
scanf("%d/%d,%d/%d", &i, &j, &k, &l); /* 输入两个分数 */
m = zxgb(j,l)/j * i; /* 求出第一个分数通分后的分子 */
n = zxgb(j,l)/l * k; /* 求出第二个分数通分后的分子 */
if(m>n )
printf("%d/%d > %d/%d\n",i,j,k,l); /* 比较分子的大小 */
else if(m==n)
printf("%d/%d = %d/%d\n",i,j,k,l); /* 输出比较的结果 */
else printf("%d/%d < %d/%d\n",i,j,k,l);
}
zxgb(a,b)
int a,b;
{ long int c;
int d;
if(a
for( c=a*b; b!=0; ) /* 用辗转相除法求a和b的最大公约数 */
{ d=b; b=a%b; a=d;
}
return((int) c/a); /* 返回最小公倍数 */
}
【4.82】参考答案:
main()
{ int a[5],i,t,k;
for (i=100;i<1000;i++)
{ for(t=0,k=1000;k>=10;t++)
{ a[t]=(i%k)/(k/10);
k/=10;
}
if(f(a[0])+f(a[1])+f(a[2])==i)
printf("%d ",i);
}
}
f(m)
int m;
{ int i=0,t=1;
while(++i<=m) t*=i;
return(t);
}
【4.83】分析:任取两个平方三位数n和n1,将n从高向低分解为a、b、c,将n1从高到低分解为x、y、z。判断ax、by、cz是否均为完全平方数。
参考答案:
main( )
{ void f( );
int i,t,a[3],b[3];
printf("The possible perfect squares combinations are:\n");
for(i=11;i<=31;i++) /* 穷举平方三位数的取值范围 */
for(t=11;t<=31;t++)
{ f(i*i,a); /* 分解平方三位数的各位,每位数字分别存入数组中 */
f(t*t,b);
if(sqrt(a[0]*10+b[0])==(int)sqrt(a[0]*10+b[0])
&& sqrt(a[1]*10+b[1])==(int)sqrt(a[1]*10+b[1])
&& sqrt(a[2]*10+b[2])==(int)sqrt(a[2]*10+b[2]))
/* 若三个新的数均是完全平方数 */
printf(" %d and %d\n",i*i,t*t); /* 则输出 */
}
}
void f(n,s) /* 分解三位数n的各位数字,将各个数字 */
int n, *s; /* 从高到低依次存入指针s所指向的数组中 */
{ int k;
for(k=1000;k>=10;s++)
{ *s = (n%k)/(k/10);
k /= 10;
}
}
【4.84】参考答案:
main()
{ int i,j,l,n,m,k,a[20][20];
printf("Please enter n,m=");
scanf("%d,%d",&n,&m);
for(i=0;i
for(j=0;j
{ printf("a[%d][%d]=",i,j);
scanf("%d",&a[i][j]);
}
for(i=0;i
{ for(j=0;j
printf("%6d",a[i][j]);
printf("\n");
}
for(i=0;i
{ for(j=0,k=0;j
if(a[i][j]>a[i][k]) k=j; /* 找出该行最大值 */
for(l=0;l
if(a[l][k]
if(l>=n) /* 没有比a[i][k]小的数,循环变量l就超过最大值 */
printf("Point:a[%d][%d]==%d",i,k,a[i][k]);
}
}
【4.85】分析:按题目的要求进行分析,数字1一定是放在第一行第一列的格中,数字6一定是放在第二行第三列的格中。在实现时可用一个一维数组表示,前三个元素表示第一行,后三个元素表示第二行。先根据原题初始化数组,再根据题目中填写数字的要求进行试探。
参考答案:
#include
int count; /* 计数器 */
main( )
{ static int a[ ]={1,2,3,4,5,6}; /* 初始化数组 */
printf("The possible table satisfied above conditions are:\n");
for(a[1]=a[0]+1;a[1]<=5;++a[1]) /* a[1]必须大于a[0] */
for(a[2]=a[1]+1;a[2]<=5;++a[2]) /* a[2]必须大于a[1] */
for(a[3]=a[0]+1;a[3]<=5;++a[3]) /* 第二行的a[3]必须大于a[0] */
for(a[4]=a[1]>a[3]?a[1]+1:a[3]+1;a[4]<=5;++a[4])
/* 第二行的a[4]必须大于左侧a[3]和上边a[1] */
if(jud1(a))
print(a); /* 如果满足题意,打印结果 */
}
jud1(s) /* 判断数组中的数字是否有重复的 */
int s[ ];
{ int i,l;
for(l=1;l<4;l++)
for(i=l+1;i<5;++i)
if(s[l]==s[i])
return(0); /* 若数组中的数字有重复的,返回0 */
return(1); /* 若数组中的数字没有重复的,返回1 */
}
print(u)
int u[ ];
{ int k;
printf("\nNo.:%d", ++count);
for(k=0;k<6;k++)
if(k%3==0) /* 输出数组的前三个元素作为第一行 */
printf("\n %d ",u[k]);
else /* 输出数组的后三个元素作为第二行 */
printf("%d ",u[k]);
}
【4.86】参考答案:
#include "string.h"
strcmbn(a,b,c) /* 数组合并函数:将数组a、b合并到 */
char a[],b[],c[];
{ char tmp;
int i,j,k,m,n;
m=strlen(a);
n=strlen(b);
for(i=0;i
{ for(j=i+1,k=i;j
if(a[j]
tmp=a[i]; a[i]=a[k]; a[k]=tmp;
}
for(i=0;i
{ for(j=i+1,k=i;j
if(b[j]
tmp=b[i]; b[i]=b[k]; b[k]=tmp;
}
i=0;j=0;k=0;
while(i
if(a[i]>b[j])
c[k++]=b[j++]; /* 将a[i]、b[j]中的小者存入c[k] */
else
{ c[k++]=a[i++];
if(a[i-1]==b[j]) j++; /* 如果a、b当前元素相等,删掉一个 */
}
while(i
while(j
c[k]='\0';
}
【4.87】参考答案:
pxn(x,n)
float x;
int n;
{ if(n==0) return(1);
else if(n==1) return(x);
else return(((2*n-1)*x*pxn(x,n-1)-(n-1)*pxn(x,n-2))/2);
}
【4.88】参考答案:
#include "stdio.h"
strout(s)
char *s;
{ if(*s!='\0')
{ strout(s+1); /* 递归调用strout函数,字符串首地址前移一个字符 */
putch(*s); /* 输出字符串首地址所指向的字符 */
}
else return; /* 遇到字符串结束标志结束递归调用 */
}
【4.89】参考答案:杨辉三角形中的数,正是(x+y)的N次方幂展开式中各项的系数。本题作为程序设计中具有代表性的题目,求解的方法很多(可以使用一维数组,也可以使用二维数组),前面我们给出用数组的答案,这里给出一种使用递归求解的方法。
从杨辉三角形的特点出发,可以总结出:
⑴ 第N行有N+1个值(设起始行为第0行);
⑵ 对于第N行的第J个值: (N>=2)
当J=1或J=N+1时: 其值为1
当J!=1且J!=N+1时: 其值为第N-1行的第J-1个值与第N-1行第J个值之和。
将这些特点提炼成数学公式可表示为:
c(x,y) = 1 x=1 或 x=N+1
c(x,y) = c(x-1,y-1) + c(x-1,y) 其它
下面给出的程序就是根据以上递归的数学表达式编制的。
参考答案:
#include
main( )
{ int i,j,n=13;
printf("N=");
while( n>12 )
scanf("%d", &n); /* 最大输入值不能大于12 */
for(i=0;i<=n;i++) /* 控制输出N行 */
{ for(j=0;j<12-i;j++)
printf(" "); /* 控制输出第i行前面的空格 */
for(j=1;j
printf("%6d", c(i,j)); /* 输出第i行的第j个值 */
printf("\n");
}
}
int c(x,y) /* 求杨辉三角形中第x行第y列的值 */
int x, y;
{ int z;
if((y==1)||(y==x+1))
return(1); /* 若为x行的第1或第x+1列,则输出1 */
else /* 否则;其值为前一行中第y-1列与第y列值之和 */
z = c(x-1,y-1) + c(x-1,y);
return(z);
}
【4.90】分析:整型数在计算机中就是以二进制形式存储的,此题的目的仅是为了学习递归程序的编程。
参考答案:
turn(n,a,k)
int n,a[ ],k;
{ if(n>0)
{ a[k]=n%2;
turn(n/2,a,k-1);
}
else return;
}
main()
{ int i,n,a[16]={0};
printf("\nPlease enter n:");
scanf("%d",&n);
turn(n,a,15);
for(i=0;i<16;i++)
printf("%d",a[i]);