【题目描述】
竖式问题。找出所有形如abc*de(三位数乘以两位数)的算式,使得在完整的竖式中,所有数字都属于一个特定的数字集合。输入数字集合(相邻数字之间没有空格),输出所有竖式。每个竖式前应有编号,之后应有一个空行。最后输出解的总数。具体格式见样例输出(为了便于观察,竖式中的空格改用小数点显示,但所写程序中应该输出空格,而非小数点)。
【样例输入】
2357
【样例输出】
<1>
..775
X..33
-----
.2325
2325.
-----
25575
The number of solutions = 1
【题目来源】
刘汝佳《算法竞赛入门经典 第2版》程序3-4 竖式问题
【解析】
此问题要求整个竖式出现的所有数字都包含于一个给定的数字集合中,因此解决问题的关键是判断一个数字是否存在于一串数字中,比如2在“2357”中存在,1则不存在。
一、原书代码
#include<stdio.h>
#include<string.h>
int main(){
int count = 0;
char s[20], buf[99];
scanf("%s", s);
for(int abc = 111; abc <= 999; abc++)
for(int de = 11; de <= 99; de++)
{
int x = abc*(de%10), y = abc*(de/10), z = abc*de;
//将整数输出到字符串buf
sprintf(buf, "%d%d%d%d%d", abc, de, x, y, z);
int ok = 1;
for(int i = 0; i < strlen(buf); i++) //strlen获取字符串长度
//strchr:在字符串s中查找单个字符
if(strchr(s, buf[i]) == NULL) ok = 0;
if(ok)
{
printf("<%d>\n", ++count);
printf("%5d\nX%4d\n-----\n%5d\n%4d\n-----\n%5d\n\n", abc, de, x, y, z);
}
}
printf("The number of solutions = %d\n", count);
return 0;
}
代码说明:
1.代码思路:先遍历(所有abc和de),后判断(是否属于输入的数字集合)。
2.判断环节全部用字符串的方式实现,使用了sprintf、strlen、strchr函数。
3.不知道为什么,对abc、de的遍历是从111、11开始的,看起来这是刻意为之,但题目中并未说明数字不包含0。
二、不用字符串函数
如果不用上面3个字符串函数,也是可以实现的,思路差不多,只不过需要自己写一个函数。
下面给出老金的代码:
#include<stdio.h>
char s[15];
//判断一个整数中数字是否属于输入的数字集合
int match(int n){
int d=0;
while(n>0){
int mod = n%10;
int i=0, flag=0;
while(s[i]!='\0'){
if(mod == (int)s[i]-48) flag = 1;
i++;
}
if(0==flag) return 0;
n /= 10;
}
return 1;
}
int main(){
int n, cnt=0;
scanf("%s", s); //输入字符串
//遍历所有3位数乘2位数
for(int i=100; i<1000; i++){
for(int j=10; j<100; j++){
int ge = i*(j%10); //个位与3位数相乘
int shi = i*(j/10); //十位与3位数相乘
int result = i*j;
//条件符合、输出竖式
if(match(i) && match(j) && match(result) &&
match(ge) && match(shi)){
cnt++;
printf("<%d>\n", cnt);
printf(" %d\n", i);
printf("X %d\n", j);
printf("-----\n");
printf("%5d\n", ge);
printf("%d \n", shi);
printf("-----\n");
printf("%5d\n\n", result);
}
}
}
printf("The number of solutions = %d", cnt);
return 0;
}
老金在match函数中利用了数字的ASCII码值比实际数字大48这个规律(比如数字0的ASCII码值为48),从而实现了int型与char型数字的比较。
本来想输入直接用整数,不用字符串,但因为第一个数字可能为0,所以只好选择字符串的输入方式。
两个代码对比下来,显然,用了那3个字符串函数确实便利了不少,节省了很多编程工夫。
那运行效率怎么样呢?
实际测试,输入0123456789,
原书代码:输出结果79121个,用时14.211s。
老金代码:输出结果81000个,用时34.161s。(其实相当于输出所有的3位数与2位数相乘的竖式)
如果将原书代码改从100、10开始遍历,输出结果81000个,用时22.863s。
看来论执行效率,原书代码也比老金的代码效率高。