C2第三周练习

高级(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*(x+x^{2}+...+x^{m-1}),然后整体除以x^{m}即可。而前者需要用公式法来求。另一个注意点就是先把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浏览器,写的时候还崩溃了一次,浪费了我生命中的宝贵时间。

第三次的难度已经有点苦于应付了,不知道之后的能不能顺利完成。。。加油吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值