C2第四周练习

第四周来的还是很仓促的。题目有点搞啊,我开始写这篇博客的时候还有道题没写出来23333.

总的来说难度还是有的(主要是第三题和第四题吧),但是有两题太搞了,写的时候感觉满满的恶意,因为主要是在考察对于奇怪输入和输出的处理。所以这次博客我应该会水过去= =

Gray码

【问题描述】
格雷码(Gray Code)是一种在位置传感器中常用的编码,其特点是每两个相邻的数的格雷码只有一个二进制位是不同的。例如,0-7的格雷码编码如下:
0    000
1    001
2    011
3    010
4    110
5    111
6    101
7    100
普通二进制编码到格雷码的转换方式如下:
Gn-1 = Bn-1
Gi = Bi+1 ^ Bi  (0<=i<n-1,n为编码的长度)
格雷码到普通二进制编码的转换方式如下:
Bn-1 = Gn-1
Bn-2 = Gn-2 ^ Bn-1
... ...
B0 = G0 ^ B1
转换公式中的Gk和Bk分别表示格雷码和二进制编码中的第k位。编码的位序从0开始,从右向左递增。
【输入形式】
从标准输入读取数据。 读入的数据为一系列的0、1字符串,长度在50个字符之内。在0、1串之前分别有选项是-b或-g,前者表示将读入的正整数作为格雷码转换成二进制码,后者表示将这些正整数作为二进制码转换成格雷码,无选项时等同于-b。 选项与编码之间,以及每行前后无多余空格。输入以EOF结束。
【输出形式】
将结果打印到标准输出上。 输出转换的结果,每个数占一行。
【输入样例】
-g0111 
-b0011 
101
【输出样例】
0100 
0010 
110
【时间限制】
1s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为graycode.c。

看着这么长实际上就是水题,直接按照上面步骤模拟就完事了。

#include<stdio.h>
#define MAXLINE 52

void trans(char[]);
void BtoG(char[]);
void GtoB(char[]);

int main()
{
	char s[MAXLINE];
	while ((scanf("%s", s)) != EOF)
	{
		trans(s);
	}
	return 0;
}


void trans(char s[])
{
	if (s[0] == '-' && s[1] == 'g')
		BtoG(s);
	else
		GtoB(s);
}

void BtoG(char s[])
{
	int i;
	printf("%d", s[2] - '0');
	for (i = 3; s[i] != '\0'; i++)
	{
		printf("%d", (s[i] - '0') ^ (s[i - 1] - '0'));
	}
	printf("\n");
}

void GtoB(char s[])
{
	int i = (s[0] == '-') ? 2 : 0;
	int j = 0;
	char t[MAXLINE];

	t[0] = s[i];
	i++;
	for (j = 1; s[i] != '\0'; i++, j++)
	{
		t[j] = (t[j - 1] - '0') ^ (s[i] - '0') + '0';
	}
	t[j] = '\0';
	printf("%s\n", t);
}

多项式运算

【问题描述】
一元多项式A = anxn + … + a1x + a0, B = bnxn + … + b1x + b0,根据运算符+、-、*,分别计算A + B、A - B、A * B。
例如,输入样例表示要计算(3x5 + 5x3 + 6)- (9x6 + 2x5 + 6x3 + x2 + 6),结果为-9x6 + x5 - x3 - x2 。
【输入形式】
输入文件为当前目录下的poly.in。 该文件由三行组成。第一行是多项式A,第二行是多项式B,第三行是一个运算符,表示所要进行的运算。 多项式中除常数项外的每一项的形式为AnxN,其中An(-100<An<100)是一个整数,表示该项的系数,x是变量名,N(0<=N<100)是该项的次数。首项系数为正数时,系数前的’+’省略;当首相系数为负数时,负号与整数之间没有空格;系数为0的项不表示;除常数项外,系数为1的项不显示系数,指数为1的项不显示指数。 各项与运算符之间可以有0个或多个空格符。
【输出形式】
输出结果写在标准输出上,占一行。 结果多项式按降幂方式排列,各项的表示形式与输入形式相同。 各项与运算符之间空一格(首项系数前负号除外)。
【输入样例】
3x5 + 5x3 + 6 
9x6 + 2x5 + 6x3 + x2 + 6 
-
【输出样例】
-9x6 + x5 - x3 - x2
【时间限制】
1s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为poly.c。

看上去也是水题,毕竟就多项式运算,题面的指数还这么低,用数组就能很快写出来了。但是这题很折磨,它的考点是处理奇怪的输入和要求奇怪的输出。输入有%dx%d,%dx,x%d还有x和%d(输出也有),有人说用sscanf,但是我确实不太会,只能暴力梭哈处理字符串了。(傻笑.jpg)

所以这题就是考察输入输出的,我这里的代码略去了这两部分,因为我写的很暴力很复杂,不优雅也不好理解,也就懒得贴了。(编码体验极差)

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
#define MAXLINE 10007
#define MAXNUM 102

void exec(char s[], int a[]);	//读取多项式存入数组a中
void printPoly(int a[]);		//输出多项式
void add(int a[], int b[], int ans[]);		//多项式相加
void minus(int a[], int b[], int ans[]);	//多项式相减
void muti(int a[], int b[], int ans[]);		//多项式相乘

int main()
{
	//FILE *in, *out;
	//in = fopen("poly.in", "r");
	//out = fopen("poly.out", "w");
	freopen("poly.in", "r", stdin);
	char poly1[MAXLINE], poly2[MAXLINE];
	char op;
	int a[MAXNUM] = { 0 };
	int b[MAXNUM] = { 0 };
	int poly[MAXNUM] = { 0 };

	fgets(poly1, MAXLINE, stdin);
	fgets(poly2, MAXLINE, stdin);
	op = getchar();

	exec(poly1, a);
	exec(poly2, b);

	if (op == '+')
		add(a, b, poly);
	else if (op == '-')
		minus(a, b, poly);
	else
		muti(a, b, poly);

	printPoly(poly);
	//fclose(in); fclose(out);
	return 0;
}


void exec(char s[], int a[])
{
    //读入多项式,存入数组a,下标为指数,值为系数
}

void printPoly(int a[])
{
    //按格式要求输出
}


void add(int a[], int b[], int ans[])
{
	int i;
	for (i = 0; i < MAXNUM; i++)
	{
		ans[i] = a[i] + b[i];
	}
}

void minus(int a[], int b[], int ans[])
{
	int i;
	for (i = 0; i < MAXNUM; i++)
	{
		ans[i] = a[i] - b[i];
	}
}

void muti(int a[], int b[], int ans[])
{
	int i, j;
	for (i = 0; i < MAXNUM; i++)
	{
		if (a[i] == 0)
			continue;

		for (j = 0; j < MAXNUM; j++)
		{
			if (b[j] == 0)
				continue;

			ans[i + j] += a[i] * b[j];
		}
	}
}

求倍数

【问题描述】
写一个程序,对于给定的一个自然数N(1<=N<=4999),和M个互不相同的十进制数字X1, X2,…,XM (M>=1), 找出N的一个最小的正倍数,使得该倍数中仅包含数字X1,X2,…,XM。
【输入形式】
输入文件为当前目录下的multiple.in,输入文件第一行为整数N,接下来M行分别列出数字 X1,X2..XM ,以EOF结束。
【输出形式】
输入文件为当前目录下的multiple.out,输出文件输出为这个倍数,如果无解输出0。在所有的测试数据中答案都不会超过500位。
【输入样例】
22 
7 
0 
1
【输出样例】
110
【时间限制】
1s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为multiple.c。

这次差不多最难的一题了,比那啥多项式和矩阵乘法不知道高到哪里去(

言归正传吧,反正看到这题的时候我就觉得是能力之外了,并没有这题的解决方法和思路。所以最终还是看了学长的解题思路,最后还是顺利AC了。

由于是500位的答案,基本上固定了数据的存储和解题思路。显然大数只能用字符串来存,做法也只能固定在构造解了。难点在构造上,显然暴力枚举是不行的,毕竟答案位数那么大。而且大数来判断是否为N的倍数也不好处理。

说起构造,第二次作业有道nprime(n位质数)的题也是差不多的思路,不过那题固定在质数所以很好判断哪些分支能继续构造。而这道题在BFS的枚举时也有判断条件。

当我们构造一个数时,假设其除以N的余数为x。那么在这个数后面添加一个数y时,除以N的余数就是10x+y了。这样如果出现之前出现过的余数,那么其后面的构造过程是完全相同的。我们就不再对这个数字进行接下来的构造。

例如输入7,用2和5构建,首先是2、5、22、25……。如果我们在22后面添加数字,添加2,那么222%7 = 12 % 7 = 5。那么222和5其实是等价的。2222与52等价,2225与55等价,所以这个构造是没有必要的,我们就没必要对222进行构造,直接略过。

基于这种构建思路,我们需要储存每个构造的数字及其除以N的余数。如果出现了N的倍数(即除以N余数为0),就输出这个数。代码框架大致如下:

由于我的构造函数写的很粗糙,并且我也不知道怎么改了,所以就不贴出来了。

#include<stdio.h>
#include<string.h>
#include<stdbool.h>
#define MAXM 11
#define MAXL 501
#define MAXN 5000
#define MAXRMD 10000

int used[MAXN] = { 0 };

struct _rmd {
	int reminder;
	char number[MAXL];
};

struct _rmd rmd[MAXRMD], temp[MAXRMD];

bool construct(int cnt, int a[], int N)
{
       /*
        构造N的倍数,每次在可能出现的数后面加上一位数
        如果除以N的余数为0,则输出并返回true
        无解则返回false
        */
}

int cmp(const void *a, const void *b)
{
	return *(int *)a - *(int *)b;
}

int main()
{
	freopen("multiple.in", "r", stdin);
	freopen("multiple.out", "w", stdout);
	int N;
	int a[MAXM];
	int cnt = 0;

	scanf("%d", &N);
	while ((scanf("%d", &a[cnt])) != EOF)
	{
		cnt++;
	}

	qsort(a, cnt, sizeof(int), cmp);
	if (!construct(cnt, a, N))
		printf("0");
	return 0;
}

PS:memset真好用

重复数全排列

【问题描述】
输入一个字符串,字符串由字母、数字组成,可能包含重复的字符。生成这些字符的不重复的全排列,并将结果打印到标准输出上。
【输入形式】
从标准输入上读入一个由字母、数字组成的字符串,字符串的长度小于100,其中包含重复的字符。
【输出形式】
向标准输出印结果。 每个排列占1行,各字符之间无空格分隔,每行由换行符结束。各行之间不必排序,但同一个排列不得重复输出。
【输入样例】
AABB
【输出样例】
AABB 
ABAB 
ABBA 
BABA 
BAAB 
BBAA
【时间限制】
20s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为pailie.c。

直接转前一篇博客就好了。话说20s的时间限制把我吓了一跳。我一开始的思路跑了有一组数据16s(BST都用上了),还有两组超时了,思路不是很准确。思路正确的话所有数据都是1s都不要。

矩阵乘法A

【问题描述】
从文件arr.in中读入一个m行k列的整数矩阵a和一个k行n列的整数矩阵b(1 < m, k, n < 200),在标准输出上输出这两个矩阵的乘积。
【输入形式】
输入文件arr.in中有m + k + 1行,前m行是矩阵a的元素aij,第m + 1行是空行,后k行是矩阵b的元素bij (-3000 < aij, bij < 3000)。
【输出形式】
输出结果为m行,每行n个元素,按整数右对齐方式输出,每个元素占相同的位数,且各个元素之间空格的最少数量应等于1。
【输入样例】
1 0 
0 1

1 1 
1 1
【输出样例】
1 1 
1 1
【时间限制】
1s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为arr.c。

又是这种奇怪输入的题= =

不过这题没多项式恶心,好歹都是数字,而且有空行来分割矩阵,分别读取一下就好了。

矩阵乘法的代码也就几行的事,主要还是输入输出。

#include<stdio.h>
#include<string.h>
#include<ctype.h>
#define MAXNUM 202
#define MAXLINE 1002

void read(int a[][MAXNUM], int b[][MAXNUM], int *m, int *k, int *n);
void compute(int a[][MAXNUM], int b[][MAXNUM], int c[][MAXNUM], int m, int k, int n);
void print(int a[][MAXNUM], int m, int k);

int main()
{
	//FILE *in, *out;
	//in = fopen("arr.in", "r");
	//out = fopen("arr.out", "w");
	freopen("arr.in", "r", stdin);
	//freopen("arr.out", "w", stdout);

	int a[MAXNUM][MAXNUM];
	int b[MAXNUM][MAXNUM];
	int ans[MAXNUM][MAXNUM];
	int m, k, n;

	read(a, b, &m, &k, &n);
	compute(a, b, ans, m, k, n);
	print(ans, m, n);

	//fclose(in); fclose(out);
	return 0;
}


void read(int a[][MAXNUM], int b[][MAXNUM], int *m, int *k, int *n)
{
	//读取文件内容,存入矩阵a和矩阵b中
        //m,k,n用指针传值
}

void compute(int a[][MAXNUM], int b[][MAXNUM], int c[][MAXNUM], int m, int k, int n)
{
	int i, j, temp;
	for (i = 1; i <= m; i++)
		for (j = 1; j <= n; j++)
            c[i][j] = 0;

	for (i = 1; i <= m; i++)
		for (j = 1; j <= n; j++)
			for (temp = 1; temp <= k; temp++)
				c[i][j] += a[i][temp] * b[temp][j];
}

void print(int a[][MAXNUM], int m, int k)
{
	int i, j;
	int max, max_width;
	for (i = 1; i <= m; i++)
	{
		max = 0;
		max_width = 0;
		for (j = 1; j <= k; j++)
		{
			if (a[i][j] > max)
				max = a[i][j];
		}
		while (max > 0)
		{
			max /= 10;
			max_width++;
		}
		for (j = 1; j <= k; j++)
		{
			printf("%*d ", max_width, a[i][j]);
		}
		printf("\n");
	}
}

需要注意的点可能就是printf("%*d ")这句了,这里max_width匹配的是*,是输出该数字占几位的。用这个来表示右对齐。具体%*d的用法可以去百度(其实我也不太会)。

 

怎么第六周的都出来了(

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值