虽然没有选C2这门课程,不过还是去听下课顺便完成作业吧,反正这学期课挺少的。

小题就算了不写了。

子串逆置

【问题描述】
输入两行字符串s和t(s和t可以含空格,length(t)≤length(s)≤50),将s串中首次与t匹配的子串逆置,并将处理后的s串输出。
【输入形式】
输入文件为当前目录下的invertsub.in。 文件中有两行字符串s和t,分别以换行符作为结束符,其中换行符可能是Linux下的换行符,也可能是Windows下的换行符。
【输出形式】
输出文件为当前目录下的invertsub.out。 输出文件只有一行,包含一个串,为要求的输出结果。行末要输出一个回车符。
【输入样例】
helloworld 
llowor
【输出样例】
herowollld
【时间限制】
1s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为invertsub.c。

在本地测试的时候文本最后没加换行debug了好久= =,逆置还是挺基础和简单的。不过这题用到strstr返回的是出现的地址,所以用指针写。

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

void rev(char *first, char *last)
{
	int temp;
	while (first < last)
	{
		temp = *first;
		*first = *last;
		*last = temp;
		first++; last--;
	}
}

int main()
{
	char s[52], t[52], *p;

	FILE *in, *out;
	in = fopen("invertsub.in", "r");
	out = fopen("invertsub.out", "w");

	fgets(s, 52, in); fgets(t, 52, in);
	s[strlen(s) - 1] = '\0';
	t[strlen(t) - 1] = '\0';

	if ((p = strstr(s, t)) != NULL)
		rev(p, p + strlen(t) - 1);

	fprintf(out, "%s\n", s);
	fclose(in); fclose(out);
}

区间

【问题描述】
给定n个闭区间[ai, bi](1 <= i <= n),这些区间的并可以表示为一些不相交的闭区间的并。要求在这些表示方式中找出包含不相交区间数目最少的方案。
【输入形式】
输入文件为当前目录下的prz.in。 该文件包含n行(3 <= n <= 50000),每行各包括两个以空格分隔的整数ai 和 bi,表示一个区间[ai, bi](1 <= ai <= bi <= 1000000)。
【输出形式】
输出文件为当前目录下的prz.out。 该文件内容为计算出来的不相交的区间。每一行都是对一个区间的描述,包括两个以空格分开的整数,分别为区间的下界和上界。 输出时将各区间按照升序排列输出。这里说两个区间[a, b]和[c, d]是按照升序排列的,是指a <= b < c <= d。
【输入样例】
5 6 1 4 10 10 6 9 8 10
【输出样例】
1 4 5 10
【时间限制】
1s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为prz.c。

这次里面算是最难的一道了吧。分析步骤如下:

(1)首先根据区间的下界排序,这里如果用复杂度的排序(我用的选择排序)好像会超时,所以用快排吧(我这是手写的快排,用自带的qsort应该会比较快)

(2)逐个比对,如果区间能够相交则合并,记录最大的上界。如果一个区间的下界比之前区间的上界还大,说明这两个区间必定不相交,输出之前的区间。

#include<stdio.h>

struct prz {
	int high;
	int low;
}p[50007];

void qsort(struct prz p[], int left, int right);
void print(struct prz p[], int n, FILE *out);
void swap(struct prz p[], int i, int j);

int main()
{
	FILE *in, *out;
	in = fopen("prz.in", "r");
	out = fopen("prz.out", "w");

	int i;
	int cnt = 0;

	while ((fscanf(in, "%d%d", &p[cnt].low, &p[cnt].high)) != EOF)
	{
		cnt++;
	}

	qsort(p, 0, cnt - 1);
	print(p, cnt, out);

	fclose(in); fclose(out);
}


void qsort(struct prz p[], int left, int right)
{
	struct prz temp;
	int i, j;

	if (left < right) {
		j = left;
		for (i = left + 1; i <= right; i++) {
			if (p[i].low < p[left].low)
				swap(p, i, ++j);
		}
		swap(p, j, left);
		qsort(p, left, j - 1);
		qsort(p, j + 1, right);
	}
}

void print(struct prz p[], int n, FILE *out)
{
	int last = 0;
	int i;
	fprintf(out, "%d ", p[0].low);

	for (i = 1; i < n; i++)
	{
		if (p[i].low > p[last].high)
		{
			fprintf(out, "%d\n%d ", p[last].high, p[i].low);
			last = i;
		}
		else if (p[i].high > p[last].high)
			last = i;
	}

	fprintf(out, "%d\n", p[last].high);
}

void swap(struct prz p[], int i, int j)
{
	struct prz temp = p[i];
	p[i] = p[j];
	p[j] = temp;
}

兑换硬币

【问题描述】
写一个程序,从标准输入上读入一个正整数N(1 <= N <=1000),计算出N元人民币兑换成1分、2分和5分的硬币,有多少种可能的组合。将结果以整数的方式输出到标准输出上,占一行。
【输入形式】
正整数N。(1 <= N <=1000)
【输出形式】
整数。
【输入样例】
1
【输出样例】
541
【时间限制】
1s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为nickle.c。

水题。暴力做会超时。

事实上如果遍历5分硬币的数量,根据剩余金额可以直接算出来有几种组合,因为只需要数2分硬币有几种情况,剩下的1分都能补足。我稍微化简了一下所以看着不是很清晰,凑合吧。

#include<stdio.h>

int count(int n)
{
	int i;
	int cnt = 0;

	for (i = 0; i <= n * 20; i++)
	{
		cnt += (n * 100 - i * 5) / 2 + 1;
	}

	return cnt;
}

int main()
{
	int n;
	scanf("%d", &n);
	printf("%d", count(n));
}

实数格式识别

【问题描述】
合法的实数书写格式分一般格式和科学格式两种。分别描述如下:
一般格式为常见的书写格式,分为整数部分和小数部分两部分,中间分用小数点.分隔。整数部分最开始可能含有正号或负号,之后为不含前导零的数字串;小数部分是由0-9十种字符组成的任意长的字符串。当小数部分为0时,小数部分和小数点可以省略。
科学格式由系数部分和指数部分两部分组成,中间用英文字母E分隔。系数部分为实数书写的一般格式;指数部分为可带有正负号数字串。
例如,+2、-1.56为一般格式的实数,而6.2E-2、-9E8为科学格式的实数。
只有小数点而没有小数部分的书写格式为不合法,例如,23.,23.E16均为不合法的实数书写格式。
编程分析哪些数的书写是正确的,是用哪种方式书写的。
【输入形式】
输入文件为当前目录下的real.in。 该文件包含一个字符串(长度不超过20个字符),以回车符结束,表示一个数据(无多余空格)。
【输出形式】
输出文件为当前目录下的real.out。 该文件有一行。如果输入数据的书写是非法的,输出Wrong;如果输入数据是用一般格式书写的,输出“Format1”;如果该数据是用科学格式书写的,输出“Format2”。输出的末尾均要以一个回车符作为结束。
【输入样例1】
+1.23
【输出样例1】
Format1
【输入样例2】
-5.1.1
【输出样例2】
Wrong
【输入样例3】
-5.1E-2
【输出样例3】
Format2
【时间限制】
1s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为real.c。

不难但是很繁琐的一道题,思路可以用状态机来完成,但是我怕出错就没这么写。一开始写了一个超级繁琐的版本后来改成下面这个版本。

普通格式与科学格式的特征区别:E
<普通格式> E [<符号>] <整数>

如果有E我们就用科学格式来判别,E前面是否为<普通格式>,后面是否为[符号]+整数。如果没有E我们就判断是否为普通格式。


普通格式的两种类型:是否有小数点
[<符号>]<整数> . <整数>
[<符号>]<整数>

所以我们根据有无小数点,判断小数点前面和后面是否分别满足条件即可。

#include<stdio.h>
#include<string.h>
#include<stdbool.h>
#include<ctype.h>

void judge(char s[], int length, FILE *out);
bool judgeDec(char s[], int first, int last);
bool judgeInt(char s[], int first, int last);
bool judgeExp(char s[], int fisrt, int last, int eindex);

int main()
{
	char s[22];

	FILE *in, *out;
	in = fopen("real.in", "r");
	out = fopen("real.out", "w");

	fgets(s, 22, in);
	s[strlen(s) - 1] = '\0';
	int length = strlen(s);

	judge(s, length, out);

	close(in); close(out);
	return 0;
}

void judge(char s[], int length, FILE *out)
{
	int i;

	for (i = 0; i < length; i++)
		if (s[i] == 'E')
			break;

	if (i + 1 == length)
		fprintf(out, "Wrong\n");
	else if (i == length)
	{
		if (judgeDec(s, 0, length - 1))
			fprintf(out, "Format1\n");
		else
			fprintf(out, "Wrong\n");
	}
	else
	{
		if (judgeExp(s, 0, length - 1, i))
			fprintf(out, "Format2\n");
		else
			fprintf(out, "Wrong\n");
	}
}

bool judgeDec(char s[], int first, int last)
{
	int pindex;
	int pflag = 0;
	bool judge = false;
	int i = (s[first] == '-' || s[first] == '+') ? first + 1 : first;

	for (pindex = first; pindex <= last; pindex++)
		if (s[pindex] == '.')
		{
			pflag++;
			break;
		}

	if (!pflag)
		judge = judgeInt(s, i, last);
	else
		judge = judgeInt(s, i, pindex - 1) && judgeInt(s, pindex + 1, last);

	return judge;
}

bool judgeInt(char s[], int first, int last)
{
	if (first > last)
		return false;

	while (isdigit(s[first]) && first <= last)
		first++;

	if (first == last + 1)
		return true;
	else
		return false;
}

bool judgeExp(char s[], int first, int last, int eindex)
{
	bool judge = false;
	int i = (s[eindex + 1] == '-' || s[eindex + 1] == '+') ? eindex + 2 : eindex + 1;
	judge = judgeDec(s, first, eindex - 1) && judgeInt(s, i, last);
	return judge;
}

在judgeDec和judgeExp我没有对left<=right进行规约, 因为调用时已经满足了这个条件。
 

N!的分解

【问题描述】
将N!分解成素数幂的乘积。
【输入形式】
从标准输入读取一个整数N(1 <= N <= 30000)。
【输出形式】
结果打印到标准输出。 输出格式为:p1^k1*p2^k2…其中p1,p2…为质数且ki>1。当ki=1时只输出pi,ki=0的项不输出。分解式中的素数按从小到大输出。
【输入样例】
5
【输出样例】
2^3*3*5
【时间限制】
1s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为decompose.c。

对2~N出现的每一个数,将其所有质因子加入质数表中记录出现次数。不过我没有记录用质数表而是直接用数组存,反正效果差不多= =

另外输出的时候特判一下就行了

#include<stdio.h>
#define MAXNUM 30001
int prime[MAXNUM] = { 0 };

void gen_factor(int n, int prime[]);
void print(int n, int prime[]);

int main()
{
	int n;
	scanf("%d", &n);
	gen_factor(n, prime);
	print(n, prime);
}

void gen_factor(int n, int prime[])
{
	int i, j, temp;
	for (i = 2; i <= n; i++)
	{
		temp = i;
		for (j = 2; j <= temp; j++)
		{
			if (temp % j == 0)
			{
				prime[j] ++;
				temp /= j;
				j--;
			}
		}
	}
}

void print(int n, int prime[])
{
	int i, first = 1;
	for (i = 2; i <= n; i++)
	{
		if (prime[i] == 1)
		{
			if (first)
			{
				first = 0;
				printf("%d", i);
			}
			else
				printf("*%d", i);
		}
		else if (prime[i] > 1)
		{
			if (first)
			{
				first = 0;
				printf("%d^%d", i, prime[i]);
			}
			else
				printf("*%d^%d", i, prime[i]);
		}
	}
}

好好学吧,这学期尽量坚持一件事。把C2的平时练习都写完然后写博客,看看能不能坚持这学期

10-07 14:36