2008年12月31日星期三

字符串中找出数字并求和

由键盘输入一个字符串,其中包括字母和数字,输出字符串中十进制数的和。
入:AJJJH FJ 378 ,DH DSAUH 1507
出:375+1507=1882

分析:
扫描字符串,发现数字标记数字起始位置。当数字变回非数字字符时,提取数字并将其转换为数字,累加数字求和。

C代码:

#include < stdio.h >
#include < stdlib.h >
#include < math.h >
#include < string.h >

#define MAX 256

int main(int argc, char **argv)
{
char buffer[MAX], ch;
int i = 0, len;
int start_flg = 0, start_pos = 0, sum = 0;
memset(buffer, '\0', sizeof(char) * MAX);

ch = getchar();
while (ch != 0x0A) {
buffer[i] = ch;
ch = getchar();
i++;
}
len = strlen(buffer);

for (i = 0; i <= len; i++) {
if (!start_flg && buffer[i] >= '0' && buffer[i] <= '9') {
start_pos = i;
start_flg = 1;
} else if (start_flg && (buffer[i] < '0' || buffer[i] > '9')) {
buffer[i] = '\0';
int tmp = atoi(buffer + start_pos);
sum += tmp;
printf("%d\n", tmp);
start_flg = 0;
}
}

printf("%d\n", sum);

return 0;
}

2008年12月30日星期二

字符串操作

由键盘输入一个不超过40个字符的字符串,已知其中有两个“A”,请你编程完成以下任务:
(1)求出每个“A”所在的位置
(2)求出两个“A”之间的字符及字符个数

C代码:

#include < stdio.h >
#include < stdlib.h >
#include < math.h >
#include < string.h >

#define MAX_LEN 40

int main(int argc, char **argv)
{
char buffer[MAX_LEN];
int len;
int p1, p2, i;
int flg = 1;
memset(buffer, '\0', sizeof(char) * MAX_LEN);

scanf("%s", buffer);
len = strlen(buffer);

for (i = 0; i < len; i++) {
if (buffer[i] == 'A' && flg) {
p1 = i;
flg = 0;
} else if (buffer[i] == 'A') {
p2 = i;
break;
}
}

printf("p1: %d, p2: %d\n", p1, p2);
printf("len: %d\n", p2 - p1);
for (i = p1; i < p2-1; i++) {
printf("%c", buffer[p2-i-1+p1]);
}
printf("\n");

return 0;
}

圆环上求素数

给出一个取数长度L(1<=L<=5),然后从1开始按顺时针方向连续取L个数字,拼成一个长为L位的数,此时共有9个长为L位的数,然后输出这9个数中的素数。
例如:L=2,此时9个长度为2位的数为:
12,23,34,45,56,67,78,89,90.其中素数有:23,67,89

分析:
先根据长度求出9个数,这里注意并没有0打头的数,所以只有9个。使用数组和下标模运算模拟环状的数据结构。使用循环计算出对应的数据,存入结果数组中。遍历数组,确定素数。

C代码:

#include < stdio.h >
#include < stdlib.h >
#include < math.h >
#include < string.h >

#define LEN 9

int main(int argc, char **argv)
{
int ring[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
int re[LEN];
memset(re, 0, sizeof(int) * LEN);
int l, i, j, flg;
scanf("%d", &l);

for (i = 0; i < 10; i++) {
for (j = 0; j < l; j++) {
re[i] = re[i] + ring[(i+j) % 10] * (int)pow((double)10, (double)(l-1-j));
}
}

for (i = 0; i < LEN; i++) {
flg = 1;
for (j = 2; j < re[i]; j++) {
if (re[i] % j == 0) {
flg = 0;
}
}
if (flg) {
printf("%d\t", re[i]);
}
}
printf("\n");

/**
for (i = 0; i < LEN; i++) {
printf("%d\n", re[i]);
}
*/

return 0;
}

2008年12月28日星期日

05年第四题 约定的密码

05年第四题 约定的密码

林林和他的几个同学对计算机程序设计都相当有兴趣,假期临近了,他们平时商量研究的一些问题想利用假期进一步完善.因为放假他们无法天天见面,因此他们决定以电子邮件来传送每个人的研究报告,但考虑邮件在传输过程中有可能出现问题,因此商定了一组加密的方式。你作为研究组的成员之一,编程将明码破解出密码。

明码方式一:由四部分组成(此四部分,两两之间用一个空格隔开,以一个$为结束标志),第一部分为数字1用来表示方式1;第二部分为一个键盘符号(不包括空格和$)组成的字符串(长度不超过30个字符);第三部分(m)、第四部分(n) 均为正整数(0<30),表示对于给定的字符串从第m个字符起,截取n个。然后将截得的字符串逆序输出则为密码。

例如:

明码的键盘输入:1 abcdefghlmnopq 3 5$

密码的屏幕输出:gfedc

明码方式二:由三部分组成(此三部分,两两之间用空格隔开,以一个$为结束标志),第一部分为数字2表示方式2;其后为两个不超过五位长的正整数(m,n,2<99999),

求这两个数从m到n之间的所有素数(质数),并将这些素数连结成的没有空格的字符串为密码。

例如:

明码的键盘输入:2 30 80$

密码的屏幕输出:3137414347515357596167717379

分析:
  本题分为两种模式,一种是字符串反向输出,另一种是求某区间内的素数。具体内容是基本算法,本体主要难度在于对输入的处理,应根据空格和$符号对输入进行拆分,在分别根据条件进行处理。

C代码:

#include < stdio.h >
#include < stdlib.h >
#include < math.h >
#include < string.h >

int main(int argc, char **argv)
{
int len, i, t;
char buffer[60];
char s[4][31], ch;
int last, current;

for (i = 0; i < 4; i++) {
memset(s[i], '\0', sizeof(char) * 31);
}

len = 0;
ch = getchar();
while (ch != 0x0A) {
buffer[len] = ch;
ch = getchar();
len++;
}
buffer[len] = '\0';

t = 0;
last = 0;
current = 0;
for (i = 0; i < len; i++) {
if (buffer[i] == ' ' || buffer[i] == '$') {
current = i;
strncpy(s[t], &buffer[last], current - last);
t++;
last = current;
}
}

if (s[0][0] == '1') {
len = strlen(s[1]);
printf("%d\n", atoi(s[3]));
for (i = atoi(s[2]); i < atoi(s[2]) + atoi(s[3]); i++) {
printf("%c", s[1][len-i]);
}
printf("\n");
} else {
int min, max, j, flg;
min = atoi(s[1]);
max = atoi(s[2]);
for (i = min; i <= max; i++) {
flg = 1;
for (j = 2; j < i; j++) {
if (i % j == 0) {
flg = 0;
break;
}
}
if (flg == 1) {
printf("%d", i);
}
}
printf("\n");
}

return 0;
}

05年复赛第三题 求两数相加的和

05年复赛第三题 求两数相加的和

对于任意输入的位长可达100位的两个正整数,求它们的和。

输入样例:
234,456
输出样例:
790

分析:
大数加法,使用数组模拟存储,加法计算方法使用循环模拟。
此部分由于C语言特点,使用了命令行参数,以后有待完善。

C代码:

#include < stdio.h >
#include < stdlib.h >
#include < math.h >
#include < string.h >

int main(int argc, char **argv)
{
int *a, *b, *c, m, n, p, i;
m = strlen(argv[1]);
n = strlen(argv[2]);

p = m>n ? m:n;

a = malloc(sizeof(int) * p);
b = malloc(sizeof(int) * p);
c = malloc(sizeof(int) * (p+1));
memset(a, 0, sizeof(int) * p);
memset(b, 0, sizeof(int) * p);
memset(c, 0, sizeof(int) * (p+1));

for (i = m-1; i >= 0; i--) {
a[i] = argv[1][m-1-i] - '0';
}

for (i = n-1; i >= 0; i--) {
b[i] = argv[2][n-1-i] - '0';
}

for (i = 0; i < p; i++) {
c[i] = a[i] + b[i] + c[i];
if (c[i] >= 10) {
c[i+1]++;
c[i] = c[i] % 10;
}
}

for (i = 0; i < m; i++) {
printf("%d", a[i]);
}
printf("\n");
for (i = 0; i < n; i++) {
printf("%d", b[i]);
}
printf("\n");
for (i = 0; i < p+1; i++) {
printf("%d", c[i]);
}
printf("\n");
if (c[p] == 0) {
for (i = p-1; i >= 0; i--) {
printf("%d", c[i]);
}
} else {
for (i = p; i >= 0; i--) {
printf("%d", c[i]);
}
}
printf("\n");

free(a); free(b); free(c);

return 0;
}

05年复赛第二题 城市的道路

05年复赛第二题 城市的道路

某城市的道路呈整齐的方格网状,东西走向的道路为M条,南北走向的道路为N条,某人住在城市的西南角A处,每天骑自行车到东北角的B处上班。为了顺便观光市容,他经常改变行车路线,他的原则是每次行车只能向北或向东,总是朝着单位的方向,最后一定到达单位.这样从A点到B点有多少种走法?
由键盘输入M和N的值(1<=20,且为整数),在屏幕上输出显示走法总数.>
例如:左图为东西向有5条,南北向有9条路,从A点(西南角)走向B点(东北角)共有495种走法.
输入样例:(键盘)
5,9
输出样例:(屏幕)
495

分析:
  本题使用二维数组进行道路的模拟,每个结点表示从(0,0)点到本结点的路线总数。
1----1

1----1
| |
| |
| |
1----2

1----1
| |
| |
| |
1----2
| |
| |
| |
1----3

1----1----1
| | |
| | |
| | |
1----2----3
| | |
| | |
| | |
1----3----6

根据此分析,路线数=左侧路线数+上方路线数,由此迭代解决此问题。

C代码:

#include < stdio.h >
#include < stdlib.h >
#include < math.h >
#include < string.h >

int main(int argc, char **argv)
{
int m, n, i, j;
long long **matrix;
scanf("%d, %d", &m, &n);
matrix = malloc(sizeof(long long *) * m);
for (i = 0; i < m; i++) {
matrix[i] = (long long *)malloc(sizeof(long long) * n);
}
for (i = 0; i < m; i++) {
matrix[i][0] = 1;
}
for (j = 0; j < n; j++) {
matrix[0][j] = 1;
}

for (i = 1; i < m; i++) {
for (j = 1; j < n; j++) {
matrix[i][j] = matrix[i-1][j] + matrix[i][j-1];
}
}

for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
printf("%lld\t", matrix[i][j]);
}
printf("\n");
}
printf("%lld\n", matrix[m-1][n-1]);

for (i = 0; i < m; i++) {
free(matrix[i]);
}
free(matrix);

return 0;
}

05年复赛第一题 不高兴的津津

05年复赛第一题 不高兴的津津

将要升入七年级的津津,希望按照每天8小时的学习时间,其他时间让他接触自己有兴趣的活动.对于家长为他安排的校外学习,超过了8小时他是不高兴的.对于给出的下一周(7天)每天上午、下午、晚上三个学习时间(正整数)安排,找出津津哪一天不高兴(周一用1表示、周二用2表示、周三用3表示.......周六用6表示,周七用7表示)。当"不高兴的一天"学习时间一样时则输出最靠前的一天。当一周没有“不高兴”的一天则输出0。

输入样例:(键盘输入)

4,3,1

4,2,1

4,3,2

4,3,1

4,3,2

3,3,1

2,2,1

输出样例:(屏幕输出)

3

分析:
本题要求对每天学习时间求和,并对和作出判断。由于一周有7天,每天三个时段,使用7行3列的二维数组存储数据,行为每天三个时段学习时间,对每一行求和,判断和是否大于8。如大于8输出当前日期序号,如一周都没有则输出0。

C代码:

#include < stdio.h >
#include < stdlib.h >
#include < math.h >

#define DAYS 7

int main(int argc, char **argv)
{
int i;
int a[7][3];

for (i = 0; i < DAYS; i++) {
scanf("%d, %d, %d", &a[i][0], &a[i][1], &a[i][2]);
}

for (i = 0; i < DAYS; i++) {
if (a[i][0] + a[i][1] + a[i][2] > 8) {
printf("%d\n", i + 1);
return 0;
}
}
printf("0\n");

return 0;
}

2008年12月16日星期二

绘制圆[趣味编程百例]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

    在屏幕上用"*"画一个空心的圆
*问题分析与算法设计
    打印圆可利用图形的左右对称性。根据圆的方程:
    R*R=X*X+Y*Y
    可以算出圆上每一点行和列的对应关系。
*程序说明与注释
#include<stdio.h>
#include<math.h>
void main()
{
    double y;
    int x,m;
    for(y=10;y>=-10;y--)
    {
        m=2.5*sqrt(100-y*y);   
/*计算行y对应的列坐标m,2.5是屏幕纵横比调节系数因为屏幕的
                                 
行距大于列距,不进行调节显示出来的将是椭圆*/
        for(x=1;x<30-m;x++)
printf(" ");     /*图形左侧空白控制*/
        printf("*");                        
/*圆的左侧*/
        for(;x<30+m;x++) printf("
");       /*图形的空心部分控制*/
        printf("*\n");                     
/*圆的右侧*/        
    }
}
运行结果
*思考题
实现函数y=x2的图形与圆的图形叠加显示

- --
马利
richard.ma

My PGP Pulic Key:
http://keyserver.pgp.com

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)

iD8DBQFJR4XW2mVtRsgDCtsRAkgzAJ9qCAVRKt4yFtDQTgJCstwNzQ2b5wCfZ1XS
Hdsm71cyB3a5dxYsR9lg+iI=
=pUOv
-----END PGP SIGNATURE-----


绘制余弦曲线和直线[趣味编程百例]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

   
在屏幕上显示0~360度的cos(x)曲线与直线f(x)=45*(y-1)+31的迭加图形。其中cos(x)图形用"*"表示,f(x)用"+"表示,在两个图形相交的点上则用f(x)图形的符号。
*问题分析与算法设计
   
本题可以在上题的基础上进行修改。图形迭加的关键是要在分别计算出同一行中两个图形的列方向点坐标后,正确判断相互的位置关系。为此,可以先判断图形的交点,再分别控制打印两个不同的图形。
*程序注释与说明
#include<stdio.h>
#include<math.h>  
void main()
{
    double y;
    int x,m,n,yy;
    for(yy=0;yy<=20;yy++) /*对于第一个y坐标进行计算并在一行中打印图形*/
    {
       
y=0.1*yy;                      
/*y:屏幕行方向坐标*/
       
m=acos(1-y)*10;       /*m:
cos(x)曲线上y点对应的屏幕列坐标*/
       
n=45*(y-1)+31;        /*n:
直线上y点对应的列坐标*/
       
for(x=0;x<=62;x++)             
/*x: 屏幕列方向坐标*/
           
if(x==m&&x==n) printf("+");  /*直线与cos(x)相交时打印"+"*/
            else
if(x==n) printf("+");   /*打印不相交时的直线图形*/
            else
if(x==m||x==62-m) printf("*");  /*打印不相交时的cos(x)图形*/
            else 
printf("
");                 
/*其它情况打印空格*/
        printf("\n");
    }
}
*运行结果
*思考题
    如何实现sin(x)曲线与cos(x)曲线图形的同时显示。

- --
马利
richard.ma

My PGP Pulic Key:
http://keyserver.pgp.com

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)

iD8DBQFJR4Sn2mVtRsgDCtsRAtZHAJ9bOwY4rUQDh2D6qcxw9xD/GRzyPwCcCkao
Be54Ko4qINBAXYJAO4tIIkw=
=GzV+
-----END PGP SIGNATURE-----


绘制余弦曲线[趣味编程百例]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

在屏幕上用"*"显示0~360度的余弦函数cos(x)曲线
*问题分析与算法设计
    如果在程序中使用数组,这个问题十分简单。但若规定不能使用数组,问题就变得不容易了。
   
关键在于余弦曲线在0~360度的区间内,一行中要显示两个点,而对一般的显示器来说,只能按行输出,即:输出第一行信息后,只能向下一行输出,不能再返回到上一行。为了获得本文要求的图形就必须在一行中一次输出两个"*"。
   为了同时得到余弦函数cos(x)图形在一行上的两个点,考虑利用cos(x)的左右对称性。将屏幕的行方向定义为x,列方向定义为y,则0~180度的图形与180~360度的图形是左右对称的,若定义图形的总宽度为62列,计算出x行0~180度时y点的坐标m,那么在同一行与之对称的180~360度的y点的坐标就
应为62-m。程序中利用反余弦函数acos计算坐标(x,y)的对应关系。
    使用这种方法编出的程序短小精炼,体现了一定的技巧。
*程序说明与注释
#include<stdio.h>
#include<math.h>
void main()
{
    double y;
    int x,m;
   
for(y=1;y>=-1;y-=0.1)         
/*y为列方向,值从1到-1,步长为0.1*/
    {
       
m=acos(y)*10;             
/*计算出y对应的弧度m,乘以10为图形放大倍数*/
        for(x=1;x<m;x++) printf(" ");
       
printf("*");               
/*控制打印左侧的 * 号*/
        for(;x<62-m;x++)printf(" ");
       
printf("*\n");            
/*控制打印同一行中对称的右侧*号*/
    }
}
*运行结果
*思考题
    如何实现用"*"显示0~360度的sin(x)曲线。

- --
马利
richard.ma

My PGP Pulic Key:
http://keyserver.pgp.com

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)

iD8DBQFJR4L12mVtRsgDCtsRAnYyAJ9ekmZRHMNkyasYBzXCX/9ztOKAzgCdEQzK
PtAXsNLxq9tKdvzXtOeGU7E=
=AvA1
-----END PGP SIGNATURE-----