5.4(非OJ实验、练习)编一个函数, 求解二元一次方程组
#include <stdio.h>
#include <math.h>
#define PRE 1e-4
#define ERROR -404404
double Solve(double,double,double,double,double,double,double*);
int main()
{
double a1,b1,c1,a2,b2,c2,x,y;
printf("请输入第一个二元一次方程x的系数,y的系数,常数项:\n");
scanf("%lf%lf%lf",&a1,&b1,&c1);
printf("请输入第二个二元一次方程x的系数,y的系数,常数项:\n");
scanf("%lf%lf%lf",&a2,&b2,&c2);
if ((x=Solve(a1,b1,c1,a2,b2,c2,&y)) == ERROR) {
printf("方程无解!\n");
} else {
printf("x=%.3f , y=%.3f",x,y);
}
return 0;
}
double Solve(double a1,double b1,double c1,double a2,double b2,double c2,double* py)
{
double d = a1*b2-a2*b1, dx = c1*b2-c2*b1, dy = a1*c2-a2*c1, ansx;
if (fabs(d) <= PRE) {
ansx = ERROR;
} else {
ansx = dx/d;
*py = dy/d;
}
return ansx;
}
现在再看这个代码感觉怪怪的,当时是用了Cramer法则去做这个,线代学的也不好,没有区分无解和无穷多解,函数传了一堆参数,应该拿个结构体封一下的。
5.6(非OJ实验、练习)分别编写函数,检测一个字符是否空格,一个字符是否数字,一个字符是否元音
#include <stdio.h>
int IsSpace (char c);
int IsNum (char c);
int IsAeiou (char c);
int main()
{
char s[101];
gets(s);
char* p ;
for (p=s;*p;p++) {
if (IsSpace(*p)) {
printf("Spc ");
} else {
if (IsNum(*p)) {
printf("Num ");
} else {
if (IsAeiou(*p)) {
printf("AEI ");
} else {
printf("Non ");
}
}
}
}
return 0;
}
int IsSpace (char c) {
return (c == ' ')?1:0;
}
int IsNum (char c) {
return (c>='0' && c<='9')?1:0;
}
int IsAeiou (char c) {
return (c == 'a' || c == 'A' || c== 'e' || c=='E' || c== 'i' || c=='I' || c=='O' || c=='o' || c=='u' || c=='U')?1:0;
}
好吧,其实没什么好说的,如果不是分别编写函数我也不会这样写,应该把三个判断写在一个函数里面好一些吧,主函数这样看起来好奇怪。
5.10(选做练习)编写函数,以两个正整数为参数,如果该两数是友好的返回TRUE,否则返回FALSE。如果这两个整数每个的约数和(除了它本身以外)等于对方我们就称这对数是友好的。例如:1184的约数和有:1+2+4+8+16+32+37+74+148+296+592=1210 1210的约数和有:1+2+5+10+11+22+55+110+121+242+605=1184
#include <stdio.h>
int AddNum (int n);
int main()
{
int m,n;
printf("请输入两个数字判断是否为友好数:\n");
scanf("%d %d",&m,&n);
int sum1,sum2;
sum1 = AddNum(m);
sum2 = AddNum(n);
if (sum1 == n && sum2 == m) {
printf("Yes!\n");
} else {
printf("No!\n");
}
return 0;
}
int AddNum (int n)
{
int i,sum = 1;
for (i = 2;i <= n/2+1 && i < n; i ++) {
if (n % i == 0) {
sum += i;
}
}
return sum;
}
函数是把参数所有的真约数加起来,后来OJ又碰到了这个题:
#include <stdio.h>
#include <math.h>
int PrimeSum (int n);
int main ()
{
int a;
scanf("%d",&a);
while (a--) {
int m,n;
scanf("%d%d",&m,&n);
if (PrimeSum(m) == n && PrimeSum(n) == m) {
printf("YES\n");
} else {
printf("NO\n");
}
}
return 0;
}
int PrimeSum (int n)
{
int i,sum=1;
for (i=2;i<=sqrt(n)+1;i++) {
if (n % i == 0 ) {
sum += i+n/i;
}
}
return sum;
}
明显还是下面这个用心一点……做了一点点优化。
6.7(非OJ实验、练习)编函数, 找出给定两维整数组A中所有鞍点。若一个数组元素A[i,j] 正好是矩阵A 第 i 行的最小值; 第 j 列的最大值则称其为 A 的一个鞍点。
#include <stdio.h>
typedef struct {
int x,y;
} Node;
int main()
{
int n,m;
printf("请输入矩阵行数列数:\n");
scanf("%d %d",&m,&n);
int i,j,k;
int a[100][100];
Node max[100],min[100]={(0,0)};
for (i = 0;i < m;i ++) {
min[i].x = 0;
min[i].y = 0;
for (j = 0;j < n;j ++) {
scanf("%d",&a[i][j]);
if (a[i][j] < a[min[i].x][min[i].y]) {
min[i].x = i;
min[i].y = j;
}
if (a[i][j] > a[max[j].x][max[j].y]) {
max[j].x = i;
max[j].y = j;
}
}
}
for (i = 0;i < m;i ++) {
for (j = 0;j < n;j ++) {
if (max[i].x == min[j].x && max[i].y == min[j].y) {
printf("(%d,%d)",i+1,j+1);
}
}
}
return 0;
}
一边读入一边处理数据,输入终止的时候就能找到每行每列的最大值坐标或者最小值左边,似乎是联机算法吧?大体思路如此,为了省时间,但是题目是编函数……。
6.14(非OJ实验、练习)编函数,先对任意给定的 m*n 阶整数矩阵的每行按递增顺序排序, 然后再按行以每行第一个元素为关键字以递增顺序排序。使
a11<a12<… <a1n a21<a22<… <a2n … … … am1<am2< …<amn 且 a11<a21< …<am1
#include <stdio.h>
#define MAXSIZE 100
int main()
{
int m,n;
scanf("%d%d",&m,&n);
int a[MAXSIZE][MAXSIZE];
int i,j,temp,temp_a[MAXSIZE];
for (i = 0; i<m; i++) {
for (j = 0; j<n; j++) {
scanf("%d",&temp);
if (j>=1) {
int k = j-1;
while (a[i][k]>temp && k>=0) {
a[i][k+1] = a[i][k];
k--;
}
a[i][k+1] = temp;
} else {
a[i][j] = temp;
}
}
if (i>=1) {
int k;
for (k = 0;k<n;k++) {
temp_a[k] = a[i][k];
}
k = i-1;
while (temp_a[0] < a[k][0] && k>=0) {
for (int l = 0; l<n; l++) {
a[k+1][l] = a[k][l];
}
k --;
}
for (int l = 0;l<n;l++) {
a[k+1][l] = temp_a[l];
}
}
}
for (i = 0; i<m; i++) {
for (j = 0; j<n; j++) {
printf("%d ",a[i][j]);
}
printf("\n");
}
return 0;
}
又用到了一边读入一边处理数据的思想,矩阵每输入一个元素,就在矩阵的这一行中按顺序插入这个元素,每输入完一行,就把这一行插入到矩阵中合适的位置,所以用了插入排序,输入结束,对数据的处理也就结束,然而用函数……
6.12(练习)设多项式P(x) = anxn+an-1xn-1+… +a1x+a0的系数和幂次存于如下表中:
幂次 | 幂次 | 幂次 | … … | 幂次 |
系数 | 系数 | 系数 | … … | 系数 |
例 P(x) = 3.0x5+4.2x3+2.1x2+7
保存成
5 | 3 | 2 | 0 |
3.0 | 4.2 | 2.1 | 7 |
设计保存多项式的数据结构并编一个函数计算多项式的值。
#include <stdio.h>
#include <math.h>
#define MAXSIZE 101
typedef struct {
double num;
int n;
} Node;
int main()
{
printf("输入多项式的项数\n");
int n;
scanf("%d",&n);
printf("输入每一项的系数和幂次\n");
int i;
Node forluma[MAXSIZE];
for (i=0;i<n;i++) {
scanf("%lf%d",&forluma[i].num,&forluma[i].n);
}
printf("输入x的值\n");
double x;
scanf("%lf",&x);
double ans=0;
for (i=0;i<n;i++) {
ans += pow(x,forluma[i].n)*forluma[i].num;
}
printf("%.3f\n",ans);
return 0;
}
存储也可以用double类型的一维数组,用下表来代表幂次,然而一旦存在幂次过高的项就会导致空间极大的浪费和求值时的不便,所以不如结构体数组,然而编写函数……。
6.21(练习)编写函数strcat把给定的两个字符串连接起来。
#include <stdio.h>
#include <string.h>
char* My_strcat(char* s1,char* s2);
int main()
{
char s1[1001],s2[1001];
scanf("%s %s",s1,s2);
printf("%s",My_strcat(s1,s2));
return 0;
}
char* My_strcat(char* s1,char* s2)
{
int i,len1,len2;
len1 = strlen(s1);
len2 = strlen(s2);
if (len1+len2 > 2000) {
return NULL;
}
for(i = len1; i<=len1+len2; i ++) {
s1[i] = s2[i-len1];
}
return s1;
}
我终于想起来要用函数编写了……注意一下复制会不会引起溢出,溢出了可不好玩。
6.6(选做练习)编函数, 把整数组中值相同的元素删除得只剩一个; 并把剩余元素全部串到前边。
#include <stdio.h>
#include <string.h>
#define MAXSIZE 101
int main()
{
int len,i;
char s[MAXSIZE];
scanf("%s",s);
len = strlen(s);
for (i = 0; i<len-1 ; i ++) {
for (int j = i+1; j<len ; j ++) {
if (s[i] == s[j]) {
for (int k = j;k<len;k ++) {
s[k] = s[k+1];
}
len --;
j --;
}
}
}
printf("%s",s);
return 0;
}
简单粗暴。
6.17(选做练习)编程序,把自然数列 1 、2 、3 、4 、5 、...成螺旋形放入方阵Amm中,并打印该方阵。例,五阶方阵 A55 的形式如下图所示。
1 | 2 | 3 | 4 | 5 |
16 | 17 | 18 | 19 | 6 |
15 | 24 | 25 | 20 | 7 |
14 | 23 | 22 | 21 | 8 |
13 | 12 | 11 | 10 | 9 |
#include <stdio.h>
int main()
{
int i=0,j=0,m,n,num;
int a[100][100]={0};
printf("请输入一共要打印的数字个数:\n");
scanf("%d",&num);
printf("请输入矩阵的阶数:\n");
scanf("%d",&m);
if (m*m != num) {
printf("INPUT ERROR!!");
return -1;
}
int cnt = 1;
int circle = 0;
while (cnt <= num) {
for (i = circle ; i <= m - 1 - circle; i ++, cnt ++) {
a[circle][i] = cnt;
}
for (i = circle + 1 ; i < m - 1 - circle; i ++, cnt ++) {
a[i][m - 1 - circle] = cnt;
}
for (i = m - 1 - circle; i > circle; i --, cnt ++) {
a[m - 1 - circle][i] = cnt;
}
for (i = m - 1 - circle; i > circle; i --, cnt ++) {
a[i][circle] = cnt;
}
circle ++;
}
for (i = 0;i < m;i ++) {
for (j=0;j<m;j++) {
printf("%5d",a[i][j]);
}
printf("\n");
}
return 0;
}
规律很明显,只是写的时候需要一点耐心和细心。
6.25(选做练习)整理名字表。编程序,输入任意顺序的名字表,将其按字典顺序排序并输出。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void Insert (char* s, char sp[100][101], int i);
int Cmp (char* s1, char* s2);//忘记有strcmp的存在了吗我?
int Min (int a, int b);
int main()
{
int n,i;
scanf("%d",&n);
char sp[100][101];
char s[101];
for (i = 0; i < n; i ++) {
scanf("%s",s);
if (i == 0) {
strcpy(sp[0],s);
} else {
Insert (s,sp,i);
}
}
for (i = 0; i < n; i++) {
printf("%s\n",sp[i]);
}
return 0;
}
void Insert (char* s, char sp[100][101], int i)
{
int j = i;
while (j > 0 && Cmp(s,sp[j-1])) {
strcpy(sp[j],sp[j - 1]);
j --;
}
strcpy(sp[j],s);
return ;
}
int Cmp (char* s1, char* s2)
{
int i,j,ret = 2;
int len = Min(strlen(s1),strlen(s2));
for (i = 0;i < len; i ++) {
if (s1[i]<s2[i]) {
ret = 1;
break;
}
if (s1[i]>s2[i]) {
ret = 0;
break;
}
}
if (ret == 2 && len == strlen(s1)) {
ret = 1;
} else {
if (len == strlen(s2) && ret == 2) {
ret = 0;
}
}
return ret;
}
int Min (int a, int b)
{
return (a<b)?a:b;
}
依然是一边读入一边排序,同样是插入排序。
6.28(选做练习)约瑟夫(Josephus)问题:古代某法官要判决 n 个犯人死刑, 他有一条荒唐的逻辑, 将犯人首尾相接排成圆圈, 然后从第 s 个人开始数起, 每数到第 m 个犯人,则拉出来处决; 然后再数 m 个,数到的犯人再处决;... ; 但剩下的最后一个犯人可以赦免。编程序,给出处决顺序,并告知哪一个人活下来。
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i,j;
int m,n,s;
scanf("%d%d%d",&n,&m,&s);
int ans = s-1;
for (i = 2; i <= n; i ++) {
ans = (ans + m) % i;
}
printf("%d",ans+1);
return 0;
}
可以用数组去模拟killing的过程,但是我这么有爱心的一个人怎么能这样做呢!