高级(C)语言程序设计2的第三次作业
这次明显有一个难度的提升,最显而易见的就是提交的时候,显示的源文件大小由原先的不到1000到了1000+甚至接近3000(表达式树那题)。动手的时候也是相当的棘手,参考了不少东西才得以A完这次的作业。就比如说表达式树这题,你如果让我不参考资料来做,那我估计花再长时间也没办法把它过了。
后缀式转中缀式
【问题描述】
将由数字和四则运算符组成的后缀表达式变换为中缀表达式。输入的后缀表达式包含的运算符不超过15个。要求转换后的中缀表达式中不应出现不必要的括号。例如,整个表达式两端的括号要省略,不影响原计算结果的括号要省略。
【输入形式】
程序从标准输入上读入一行字符串,是一个合法的后缀表达式,数字和运算符之间由空格分隔。其中的数字可以是整数,也可以是带有小数部分的浮点数。
【输出形式】
向标准输出打印结果。 输出只有一行,是转换后的中缀表达式,并且 1. 各分量(包括括号)紧密输出,不使用空格进行分隔; 2. 在转换前后各运算数的出现顺序不变; 3. 浮点数保留输入时的小数位数。
【输入样例】
4 7 - 2.1 5 + * 7.1 9 - /
【输出样例】
(4-7)*(2.1+5)/(7.1-9)
【时间限制】
1s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为convert.c。
做题的话上一篇博客已经解释的很详细了,这里简单吐槽一下。这题明显是这次难度最高的一题了。开始老师说好的简单呢?说好的没有什么数据结构呢?(哭)
不过虽然不太熟练树,好在还是记得一点的,而且还有以前的代码,这样复习一遍也挺好。但是如果不让我看网上的参考资料以及以前的源码,我估计凭自己现在的实力肯定没办法过的。
N的阶乘
【问题描述】
精确计算N的阶乘。其中,N可能是小于200的任意正整数。
【输入形式】
输入文件为当前目录下的factor.in。 该文件只包含一个正整数,表示需要求该正整数的阶乘。
【输出形式】
输出文件为当前目录下的factor.out。 该文件只包含一个正整数,表示该正整数的阶乘,每行最多输出50个数字。
【输入样例】
57
【输出样例】
40526919504877216755680601905432322134980384796226
602145184481280000000000000
【时间限制】
1s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为factor.c。
一看就是高精度问题了,以前还是挺怕写这玩意的。不过好在这个是大整数乘以小整数,可以直接用乘法的运算列算式的方式来求。难度比大整数相加减乘除低了不少,A完之后才发现挺简单的。
#include<stdio.h>
#include<string.h>
#define MAXLENGTH 10007
#define NEWLINE 50
int mutiply(int[], int, int, int[]);
void reverse(int[], int);
void factor(int, FILE*);
int main()
{
FILE *in, *out;
in = fopen("factor.in", "r");
out = fopen("factor.out", "w");
int n;
fscanf(in, "%d", &n);
factor(n, out);
fclose(in); fclose(out);
}
void reverse(int a[], int n)
{
int i = 0, j = n - 1;
int c;
while (i < j)
{
c = a[i];
a[i] = a[j];
a[j] = c;
i++; j--;
}
}
/*大整数乘小整数,答案储存在ans中,返回ans的长度*/
int mutiply(int a[], int n, int b, int ans[])
{
int i, j;
//reverse(a, n);
int muti = 0; //表乘积
int cin = 0; //表进位
for (i = 0; i < n; i++)
{
muti = a[i] * b + cin;
cin = muti / 10;
ans[i] = muti % 10;
}
while(cin > 0)
{
ans[i++] = (cin % 10);
cin /= 10;
}
//reverse(ans, i);
return i;
}
void factor(int n, FILE *out)
{
int a[MAXLENGTH] = {1};
int ans[MAXLENGTH];
int num = 1;
int i, j;
for (i = 1; i <= n; i++)
{
num = mutiply(a, num, i, ans);
memset(a, 0, 10007 * sizeof(int));
for (j = 0; j < num; j++)
a[j] = ans[j];
memset(ans, 0, 10007 * sizeof(int));
}
reverse(a, num);
for (i = 0; i < num; i++)
{
fprintf(out, "%d", a[i]);
if((i + 1) % NEWLINE == 0)
fputc('\n', out);
}
}
用int储存大整数的每一位,当然用字符串应该也没有太大问题。reverse是仿照逆转字符串写的,mutiply是模拟竖式法用a乘b。首先逆转a,然后用乘法规则写就行,最后进位可能会超过一位所以要注意处理一下,每位只保留一个一位数即可。答案储存在ans中,最后逆转一下。
但是这里需要做连续的乘法,即每一次ans都会成为下一次的a,所以逆转过程可以省略注释掉了,最后输出的时候记得倒转回来就行。factor函数写的不太好,应该可以优化,不过我这里懒得改了。
凸多边形面积
【问题描述】
【输入形式】
从标准输入读取N(3≤N≤15)行,每行两个数字(由空格隔开),分别表示该点的X、Y坐标(0≤X,Y≤32767)。所有点的坐标互不相同,且按顺时针次序给出。
【输出形式】
向标准输出打印一个浮点数,是该多边形的面积。该浮点数保留两位小数。
【输入样例】
3 3
3 0
1 0
1 2
【输出样例】
5.00
【时间限制】
2s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为points.c。
做过的水题,思路是将多边形分解成小三角形来计算面积。当然有公式直接算也可以。
由于没有math.h,所以我找了一个不用sqrt的版本来求三角形面积。(话说连stdbool.h这种偏的头文件都有,不给math.h是个什么操作)
#include<stdio.h>
double getS(double, double, double, double, double, double);
int main()
{
double x1, x2, x3, y1, y2, y3;
double S = 0;
scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
while ((scanf("%lf%lf", &x3, &y3)) != EOF)
{
S += getS(x1, y1, x2, y2, x3, y3);
x2 = x3; y2 = y3;
}
printf("%.2lf", S);
return 0;
}
double getS(double x1, double y1, double x2, double y2, double x3, double y3)
{
double a1, b1, a2, b2;
a1 = x1 - x2;
b1 = y1 - y2;
a2 = x1 - x3;
b2 = y1 - y3;
return (a1 * b2 - a2 * b1 >= 0) ? (a1 * b2 - a2 * b1) / 2 : -(a1 * b2 - a2 * b1) / 2;
}
浮点计算
【问题描述】
计算 k *∑(x^i), -m ≤ i ≤ n,精确到小数点后14位(最后要求四舍五入)。
【输入形式】
从文件sigma.in中顺序读入4个由空格分隔的正整数k、x、m、n。(1≤ k、x、m、n ≤ 100)。
【输出形式】
将结果写到标准输出,其中小数占14位,不足部分补零,最后输出一个回车。(输入数据保证输出结果小于2^53。)
【输入样例】
1 10 5 5
【输出样例】
111111.11111000000000
【时间限制】
1s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为sigma.c。
乍一看是不是很简单的水题?实际上我感觉很难= =可能难度不亚于表达式那题。可能是我没接触过这种精度要求高的题吧。
开始的时候直接用for写,直接被精度卡死。包括x的正数幂和负数幂相加的时候都会有精度损失。卡的脑壳痛,没办法只能借鉴了学长的思路和代码,最后才A的= = 只能说自己还是太菜了
由于保证了输出结果在longlong范围内,所以基本思路是x的正整数幂用long long 保存,负数幂用double保存。最后的时候不要直接相加而是分开输出。
另外计算的时候,正数幂用什么方法都无所谓,但是负数幂是不可以用for循环然后每次1/x的,这样会造成很大的精度误差。而是用公式法来求,先求出,然后整体除以
即可。而前者需要用公式法来求。另一个注意点就是先把k乘上去,否则会把除法的误差乘以k倍。
顺便这里不让用math.h所以pow还得自己写。。。。
另外就四个整数的输入,你让我用文件读入,输出到标准输出是几个意思。
#include<stdio.h>
void compute(int, int, int, int);
double computeSp(int, int, int, int);
long long power(int, int);
int main()
{
FILE *in;
in = fopen("sigma.in", "r");
int k, x, m, n;
fscanf(in, "%d%d%d%d", &k, &x, &m, &n);
compute(k, x, m, n);
fclose(in);
return 0;
}
void compute(int k, int x, int m, int n)
{
if (x == 1)
{
printf("%.014lf\n", computeSp(k, x, m, n));
return;
}
double dec;
char d[20];
long long integer = 0;
int i = 0;
dec = 1.0 * k * (1 - power(x, m)) / (1 - x);
for (i = 0; i < m; i++)
{
dec /= x;
}
while (dec > 1)
{
dec -= 1;
integer += 1;
}
integer += k * (1 - power(x, n + 1)) / (1 - x);
printf("%lld", integer);
sprintf(d, "%.014lf", dec);
printf("%s\n", d + 1);
}
/*compute when x = 1*/
double computeSp(int k, int x, int m, int n)
{
return k * (m + n + 1);
}
/*pow: return a^b*/
long long power(int a, int b)
{
int i;
long long ans = 1;
for (i = 0; i < b; i++)
ans *= a;
return ans;
}
数据的序号
【问题描述】
将N(1<= N <= 200000)个整数小到大连续编号,相同的数应具有相同的编号。并按这N个数输入时的顺序输出它们的编号序列。例如,设输入数据为 5 3 4 7 3 5 6,则输出数据为3 1 2 5 1 3 4。
【输入形式】
从标准输入读取数据。 输入包含N个数字(1<= N <= 200000),之间由空格分隔,以回车符作为结束
【输出形式】
计算结果输出到标准输出。 按这N个数输入时的顺序输出它们的编号序列。每个序号之后紧跟一个空格符,最后输出回车符。
【输入样例】
5 3 4 7 3 5 6
【输出样例】
3 1 2 5 1 3 4
【时间限制】
1s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为data.c。
水题,2016的期末题吧,还是很和善的= =
思路就是先把数据排序然后标序号,然后把数据排回来,最后输出序号。
学习了下C怎么写qsort的cmp,不知道记不记得住。还是C++的容易记一点。
#include<stdio.h>
#include<stdlib.h>
struct _data{
int data;
int index;
int num;
}d[200007];
int cmp_data(const void *p1, const void *p2);
int cmp_index(const void *p1, const void *p2);
void number(struct _data d[], int n);
void print(struct _data d[], int n);
int main()
{
int cnt = 0;
int i;
while((scanf("%d",&d[cnt].data)) != EOF)
{
d[cnt].index = cnt;
cnt++;
}
qsort(d, cnt, sizeof(d[0]), cmp_data);
number(d, cnt);
qsort(d, cnt, sizeof(d[0]), cmp_index);
print(d, cnt);
}
int cmp_data(const void *p1, const void *p2)
{
return ((struct _data *)p2)->data < ((struct _data *)p1)->data;
}
int cmp_index(const void *p1, const void *p2)
{
return ((struct _data *)p2)->index < ((struct _data *)p1)->index;
}
void number(struct _data d[], int n)
{
int i;
int num = 1;
d[0].num = num;
for (i = 1; i < n; i++)
{
if (d[i].data > d[i - 1].data)
num++;
d[i].num = num;
}
}
void print(struct _data d[], int n)
{
int i;
for (i = 0; i < n; i++)
{
printf("%d ", d[i].num);
}
printf("\n");
}
守护全世界最好的EDGE浏览器,写的时候还崩溃了一次,浪费了我生命中的宝贵时间。
第三次的难度已经有点苦于应付了,不知道之后的能不能顺利完成。。。加油吧