PS:本题解是直接粘贴oj上通过了的代码,也就是考场上做出来的。部分方法比较笨,也是考场上我的第一反应,敬请谅解。
时间限制: 1 Sec 内存限制: 128 MB
提交: 1130 解决: 112
[提交][状态][讨论版]
用指向函数的指针设计通用非线性方程牛顿法求解函数Newton(f,df,x),求任意非线性方程f(x)=0在初始值x0附近的近似解,要求近似解精确到epsilon(1E-5)。其原型如下:
double Newton (double (*fun)(double), double (*dfun)(double),double x0);
其中,fun是指向原函数f(x)的函数指针,dfun是指向导函数f'(x)的函数指针,x0是求解方程近似解的初始值。
说明:非线性方程牛顿法求解公式如下:
xk+1 = xk - f(xk)/ f'(xk)
其中,xk表示第k步的x值,xk+1表示第k+1步的x值,f(xk)为原函数在xk处的值,f'(xk)为导函数在xk处的值。
当xk+1-xk的绝对值小于epsilon时,结束迭代,得到近似解xk+1。当在xk处的导函数值小于epsilon时,认为零作为了除数,直接返回INF(即return 1.0/0.0;,该语句用于返回INF)。
在已给出的代码中,f1()、df1()、f2()、df2()、f3()和df3()6个C语言函数分别用于计算如下3个数学函数f1(x) = x3 - 10x2 + 3x + 20、f2(x) = x3 - 6x - 1和f3(x) = x3 + 10x - 20及其导函数的在指定x处的值。
程序主框架如下(提交时不要包含在内):
#include
#include
#include
double f1(double);
double df1(double);
double f2(double);
double df2(double);
double f3(double);
double df3(double);
double Newton(double (*fun)(double), double (*dfun)(double), double x0);
int main()
{
double x0;
int n;
scanf("%d%lf",&n,&x0);
switch(n)
{
case 1:
printf("%.5f\n", Newton(f1,df1,x0));
break;
case 2:
printf("%.5f\n", Newton(f2,df2,x0));
break;
case 3:
printf("%.5f\n", Newton(f3,df3,x0));
break;
default:
printf("error1\n");
exit(0);
}
return 0;
}
double f1(double x) {
return x*x*x-10*x*x+3*x+20.0;
}
double df1(double x) {
return 3*x*x-20*x+3;
}
double f2(double x) {
return x*x*x-6*x-1;
}
double df2(double x) {
return 3*x*x-6;
}
double f3(double x) {
return x*x*x+10*x-20;
}
double df3(double x) {
return 3*x*x+10;
}
一个整数和一个双精度数,其中整数代表要求解的非线性方程的编号(1~3),双精度数为方程求解x0的初始值
方程的近似解,精确到小数点后5位
说明:输出格式由题目框架设定,无需关注输出格式。
1 -1
-1.20865
double Newton (double (*fun)(double), double (*dfun)(double),double x0){
double x1=0,s=0;
s=fun(x0)/dfun(x0);
x1=x0-s;
if(fabs(dfun(x0)) < 1e-5)
return 1.0/0.0;
if(fabs(s) < 1e-5)
return x1;
else{
x0=x1;
return Newton(fun,dfun,x0);
}
}
本题卡的两个点:
在最后递归时要记得把x1的值传给新的x0,让新x0等于旧x1,让x0更新换代起来;
此题一开始我在本地测试答案一直都是-1.0000,原因是一开始的先入为主,把x1定义为整型变量了,那么返回的x1值就小数点不可能有数字了,注意x1、s要定义为double型;
注意:本题主函数中有
时间限制: 1 Sec 内存限制: 128 MB
提交: 1474 解决: 157
[提交][状态][讨论版]
Luhn算法是一种广泛使用的证件号码(由若干数字组成,长度不定)“模10”校验算法。其计算过程为:
1、从卡号最未位数字开始,逆向将奇数位(1、3、5等)求和。
2、从卡号最未位数字开始,逆向将偶数位数字乘2后求和(说明:如果乘2得到的是两位数,则将乘2的结果减9后参与求和)。
3、将奇数位和与偶数位和相加,通过判断相加结果是否是10的整数倍实现校验。
例如对于卡号5432123456788881,其各位数字编号如下表所示:
则其“模10”校验计算过程为:
1、奇数位和 = 1+8+8+6+4+2+2+4 = 35
2、偶数位和 = (8*2-9)+(8*2-9)+(7*2-9)+(5*2-9)+(3*2)+(1*2)+(3*2)+(5*2-9)
= 7+7+5+1+ 6+2+6+1 = 35
3、奇数位和+偶数位和=35+35=70, 结果是10的整数倍,校验通过。
请编写函数CheckLuhn(),完成若干组证件号码的Luhn校验,要求函数原型为:
int CheckLuhn(const char * cardId , int sum[2]);
其中,cardId是待校验证件号码字符串,sum是由两个元素构成的整型数组,sum[0]用于存储奇数位和,sum[1]用于存储偶数位和。如果通过校验,函数返回0,否则返回1。
请在已给出的宏定义、函数原型、驱动main函数代码的基础上完成题目。
程序主框架如下(注意,只提交题目要求的函数):
#include
#include
#include
#define MAX_LEN 128
int CheckLuhn ( const char * cardId, int sum[2] );
int ReadLine(char *s);
int ReadLine(char *s)
{
int n = 0, ch = 0;
while((ch = getchar()) != '\n' && ch != EOF && n < MAX_LEN - 1)
s[n++] = ch;
s[n]='\0';
return n;
}
int main()
{
int s[2]={0}, r;
char id[MAX_LEN];
while (ReadLine(id) > 0) {
r = CheckLuhn(id, s);
printf("%s,R=%d\t%d\t%d\n", id, r, s[0], s[1]);
}
return 0;
}
若干行号码字符串
四部分内容。第一部分为校验号码,第二部分为校验结果,第三、第四部分分别为奇数位和与偶数位和。
说明:输出格式由题目框架设定,无需关注输出格式。
4342560238811238
4342560238811238,R=0 32 38
注意:在设计的函数中不需要进行任何数据输出,如需查看运算结果,请在提交前删除相关数据输出代码。
int CheckLuhn(const char * cardId , int sum[2]){
int n,i,mn=0,s=0;
sum[0]=sum[1]=0;
n=strlen(cardId);
if(n%2 == 0){
for(i = 0;i < n;i++){
if(i%2 != 0){
sum[0]=sum[0]+cardId[i]-48;
}
if(i%2 == 0){
if(cardId[i] >= '5')
mn=(cardId[i]-48)*2-9;
else mn=(cardId[i]-48)*2;
sum[1]=sum[1]+mn;
}
}
s=sum[0]+sum[1];
if(s % 10 == 0)
return 0;
else return 1;
}
if(n%2 != 0){
for(i = 0;i < n;i++){
if(i%2 == 0){
sum[0]=sum[0]+cardId[i]-48;
}
if(i%2 != 0){
if(cardId[i] >= '5')
mn=(cardId[i]-48)*2-9;
else mn=(cardId[i]-48)*2;
sum[1]=sum[1]+mn;
}
}
}
s=sum[0]+sum[1];
if(s % 10 == 0)
return 0;
else return 1;
}
本题卡的点:
一定一定在卡的时候要认真读题,认真看题目给的图。对应好每一位。一开始我只考虑了题目给的两个样例,这两个样例恰好都是16位(偶数位),我的错误代码就都跑的通,但提交之后答案错误。我就自己试图写了个样例“123”,一共有3位,发现到奇数位个码的话,跟偶数位就恰好是相反的(因为指针第一个数一直都是从0开始的),这个时候要把奇数位重新考虑,就只是跟偶数位的思路一样,反一下就行。
注意:本题输入的是字符串,运算时数字对应的是其ASCII码值,所以记得减去48得到数字本身值。
时间限制: 1 Sec 内存限制: 128 MB
提交: 989 解决: 98
[提交][状态][讨论版]
机动车车牌由3部分组成,分别是:省份简称、地级市字母代码、6位或5位车牌号(由大写字母和数字组成,新能源汽车为6位车牌号,普通车辆为5位车牌号),车牌号至少包含一位数字。根据车牌号实现机动车车辆限行,其规则如下: 新能源汽车不限号;普通车辆星期一限行尾号1和6,星期二限行尾号2和7,星期三限行尾号3和8,星期四限行尾号4和9,星期五限行尾号5和0,星期六和星期天所有车辆均不限行。
车牌尾号为车牌中数字的最后一位,如果车牌号最后一位不是数字,则从后往前找到的第一个数字即为车牌尾号。例如03D4J的尾号为4。
现要求编写机动车车辆限行检测函数,其原型如下:
int Judge(char *plate_num, int day);
其中,plate_num是用来存储车牌号的字符串指针,day代表星期的整型量(1~7分别代表星期一到星期日)。
当plate_num(长度小于5或大于6、不包含数字、包含非法字符)或day(小于1或大于7)错误时,返回-1;当该车牌号被限行时,返回1,否则返回0。
主程序框架如下:
#include
#include
#define MAX_LEN 10
int Judge(char *, int);
int ReadLine(char *s);
int ReadLine(char *s)
{
int n = 0, ch = 0;
while((ch = getchar()) != '\n' && ch != EOF && n < MAX_LEN - 1)
s[n++] = ch;
s[n]='\0';
return n;
}
int main()
{
char str[MAX_LEN];
int n;
while (ReadLine(str) > 0){
scanf("%d", &n); /* 星期 */
getchar();
printf("%d\n", Judge(str, n));
}
return 0;
}
说明:输出格式由题目框架设定,无需关注输出格式。
注意:在设计的函数中不需要进行任何数据输出,如需输出运算结果,请在提交前删除相关代码.
int Judge(char *plate_num, int day){
int n,i,j,k;
n=strlen(plate_num);
if(n<5 || n>6 || day<1 ||day>7)
return -1;
for(i = 0;i < n;i++){
if(plate_num[i] < '0' || (plate_num[i] > '9' && plate_num[i] < 'A')||plate_num[i] > 'Z')
return -1;
}
for(j = 0;j < n;j++){
if(plate_num[j] >= '0' && plate_num[j] <= '9')
break;}
if(j == n)
return -1;
if(n == 6)
return 0;
if(n == 5){
for(k = 4;k >= 0;k--){
if(plate_num[k] >= '0' && plate_num[k] <= '9'){
if(day == 1){
if(plate_num[k] == '1' || plate_num[k] == '6')
return 1;
else return 0;}
if(day == 2){
if(plate_num[k] == '2' || plate_num[k] == '7')
return 1;
else return 0;}
if(day == 3){
if(plate_num[k] == '3' || plate_num[k] == '8')
return 1;
else return 0;}
if(day == 4){
if(plate_num[k] == '4' || plate_num[k] == '9')
return 1;
else return 0;}
if(day == 5){
if(plate_num[k] == '5' || plate_num[k] == '0')
return 1;
else return 0;}
if(day == 6 || day == 7)
return 0;
}
}
}
}
本题是我做出来三道题中,第一个有思路的,也是第一个做的题(我是从后往前做的)
本题卡的点:
一开始注意到了“从后往前找到的第一个数字即为车牌尾号”自己写代码的时候就又忘了,本题也没有输入,就硬着头皮交了一次,显示通过了80%,后来第一反应到自己是这错了把for循环条件改了一下,还好反应的快,没有了浪费时间。
其他这道题就没有什么了,疯狂码字而已,注意n,day,plate_num[]分别代表什么别搞混就行。注意for(i = n;i >= 0;i--)就好,此次考试两题的for循环都是从后往前,打破以往常规。
时间限制: 1 Sec 内存限制: 128 MB
提交: 207 解决: 20
[提交][状态][讨论版]
某水果店使用文本文件记录每种水果的进货和出货量(单位:公斤),文件中的每一行表示一种水果记录,各行第一列表示水果名称,第二列、第三列分别表示进货量和出货量,各列间用空白分隔。假设水果已归类,不存在重复现象。例如:
Apple 50.5 20.3
Banana 30 10.2
Orange 100 80.6
...
为实现水果店库存排序,要求编写如下两个函数:
1、文件读取函数,其原型如下:
int loadStock(pFInfo stocks, const char *fname);
其中,stocks是结构体类型的指针,用于存储读取的库存记录,fname是需要读取的水果库存记录文本文件的文件名指针,如"record.txt"。函数返回成功读取的记录条数。假定stocks指针指向的内存空间已经预先分配。
2、按照水果库存量(库存量=进货量-出货量)降序对记录进行排序并输出到指定文件的函数,其原型如下:
void sortAndSaveStock(pFInfo stocks, int n, char *fname);
其中,stocks是结构体类型的指针,用于存储读取的库存记录,n是水果库存记录总数,fname是指定的输出文本文件的文件名指针,如"sorted_record.txt"。输出时所有小数保留1位小数。
文本文件样例可使用wget命令在SSH环境中获取,命令: wget http://202.117.179.201/attach/record.txt
程序主体框架如下(注意只提交题目要求的函数):
#include
#include
#define MAX_NAME_LEN 20
#define MAX_FRUIT_LEN 20
typedef struct{
char name[MAX_NAME_LEN];
float in;
float out;
}FInfo, *pFInfo;
int loadStock(pFInfo, const char *);
void sortAndSaveStock(pFInfo, int, char *);
int main(int argc, char *argv[])
{
FInfo fruitStock[MAX_FRUIT_LEN];
if (argc < 3)
{
printf("Usage: %s \n", argv[0]);
exit(EXIT_FAILURE);
}
/* read stock information from txt file */
int n = loadStock(fruitStock, argv[1]);
if ( n > 0) sortAndSaveStock(fruitStock, n, argv[2]);
return 0;
}
说明:在设计的函数中无需任何控制台输出,文件输出时所有数值量均保留一位小数,水果名称、进货量与出货量间用一个空格分隔,每个水果一行,最后一行无换行。
注意:在设计的函数中不需要进行任何数据输出至显示器,如需在显示器上输出运算结果,请在提交前删除相关代码。 在文件写入的时候,注意不要加入任何多余的字符(回车、换行及空格等)。
时间限制: 1 Sec 内存限制: 128 MB
提交: 110 解决: 14
[提交][状态][讨论版]
现需要对一个以'.'、'?'或'!'为终止字符的英文句子按单词实现反转。现假定:
1、每次反转只针对一行完整的句子,如果输入不是一个完整句子,则输出"Sentence needs a terminating character. (./?/!)\n\n";
2、所有句子均无前导后续分隔符;
3、除终止符和分隔符外,其它标点符号与单词被认为是一个整体,并且不能独立存在。
如:
原文为:I like C langage, but he is only interested in football.
反转为:football in interested only is he but langage, C like I.
程序主体已经完成,要求实现如下两个函数:
1、单词分割及提取函数,其原型如下:
char ** splitSentenceWords(char *str , const char *delim, size_t n);
其中,str为指向句子原文字符串的指针,delim为指向可能出现的单词分隔符构成的字符串的指针,n为单词个数。函数返回分割结果的字符型二级指针。函数调用完成后,必须手工释放返回的二级指针指向的指针数组占用的内存。
2、句子按单词反转函数,其原型如下:
char * revSentenceWords(char *str, const char *delim, const char *hyphen);
其中,str为指向句子原文字符串的指针,delim为指向可能出现的单词分隔符构成的字符串的指针,hyphen指向结果句子中连接各单词的字符串。函数返回指向反转结果的指针。函数调用完成后,必须手工释放返回的指针指向的字符串占用的内存。
程序主体框架如下(注意只提交自己补足的函数代码,下面的代码请勿提交):
#include
#include
#include
#define MAXLENGTH 1024
char* revSentenceWords(char *, const char *, const char *);
char** splitSentenceWords(char *, const char *, size_t);
char isSentence(const char *, const char *);
size_t getWordsCnt(const char *, const char *);
int ReadLine(char *, int);
int ReadLine(char *str, int len)
{
int n = 0, ch = 0;
while((ch = getchar()) != EOF && ch != '\n' && n < len - 1)
str[n++] = ch;
str[n]='\0';
return n;
}
int main(void)
{
char s[MAXLENGTH];
char *p,**q;
char delim[] = " \t\n\r";
char term[] = ".?!";
char hyphen[] = " ";
int i, wc = 0;
ReadLine(s, MAXLENGTH);
if (isSentence(s, term))
{
p = revSentenceWords(s, delim, hyphen);
puts(p);
wc = getWordsCnt(p, delim);
printf("WordsCnt= %d\n", wc);
q = splitSentenceWords(p, delim, wc);
for(i = 0; i < wc; i++)
{
puts(q[i]);
}
free(q);
free(p);
}
return(0);
}
char isSentence(const char *s, const char *term)
{
char terminator = 0;
size_t len = 0;
len = strlen(s);
terminator = s[len - 1];
if(!strchr(term, terminator))
{
printf("Sentence needs a terminating character. (./?/!)\n\n");
exit(1);
}
return terminator;
}
size_t getWordsCnt(const char *s, const char *delim)
{
size_t cnt = 0;
while(*s)
{
if((!strchr(delim, *s) && (strchr(delim, *(s + 1)))) || (*(s + 1) == '\0' && (!strchr(delim, *s))))
{
cnt++;
}
s++;
}
return cnt;
}
说明:输出格式由题目框架设定,无需关注输出格式。
注意:在设计的函数中不需要进行任何数据输出,如需输出运算结果,请在提交前删除相关代码。
D、E两题考场上完全没有思路,总结来看还是对结构和文件这两张没学扎实。把问题先放到这儿,期待日后某天有能力再来解决这两道题