数据结构PTA练习题4

1. 高精度数加法

高精度数是指大大超出了标准数据类型能表示的范围的数,例如10000位整数。很多计算问题的结果都很大,因此,高精度数极其重要。

一般使用一个数组来存储高精度数的所有数位,数组中的每个元素存储该高精度数的1位数字或多位数字。
请尝试计算:N个高精度数的加和。这个任务对于在学习数据结构的你来说应该是小菜一碟。

输入格式:

第1行,1个整数N,表示高精度整数的个数,(1≤N≤10000)。

第2至N+1行,每行1个高精度整数x, x最多100位。

输出格式:

1行,1个高精度整数,表示输入的N个高精度数的加和。

代码长度限制-16 KB

时间限制-100 ms

内存限制-1 MB

完整代码:

利用字符数组存储高精度数,两数相加看成一个新的加数再与另一个数相加,如此循环下去,需要注意的是进位的处理。

这里为了方便先将字符串反序求得结果再返回来

#include <cstdio>
#include <string>
#include <iostream>
using namespace std;

char a[1000], b[1000], c[1000];
//利用y对字符串x反序
void turn(char x[], char y[])
{
	int len, i, j;
	len = strlen(x);
	j = len - 1;
	for (i = 0; i < len; i++)
	{
		y[i] = x[j];
		j--;
	}
	y[len] = '\0';
	strcpy(x, y);
}

int main()
{
	int i, lena, lenb;
	//加数和与进位
	int	sum = 0, up = 0;
	int n;
	scanf("%d", &n);
	//第一个加数
	cin >> a;
	//只有一个加数时
	if (n == 1)
	{
		cout << a;
		return 0;
	}
	//循环,每次两个数相加
	for (int k = 1; k < n; k++)
	{
		//第二个加数
		cin >> b;
		//因为要从后往前计算,所以将字符串反序方便进位操作
		turn(a, c);
		turn(b, c);
		lena = strlen(a); lenb = strlen(b);
		//处理和和进位
		for (i = 0; i < lena && i < lenb; i++)
		{
			sum = up + (a[i] - '0') + (b[i] - '0');
			if (sum >= 10)
			{
				up = 1;
				sum -= 10;
			}
			else up = 0;
			//用c保存a与b相加的结果,赋值给a方便继续操作
			c[i] = sum + '0';
		}
		if (lena > lenb)
		{
			for (; i < lena; i++)
			{
				sum = a[i] + up - '0';
				if (sum >= 10)
				{
					up = 1;
					sum -= 10;
				}
				else up = 0;
				c[i] = sum + '0';
			}
		}
		if (lenb > lena)
		{
			for (; i < lenb; i++)
			{
				sum = b[i] + up - '0';
				if (sum >= 10)
				{
					up = 1;
					sum -= 10;
				}
				else up = 0;
				c[i] = sum + '0';
			}
		}
		if (up == 1) c[i++] = '1';
		up = 0;
		c[i] = '\0';
		//清空方便进入下一次循环
		memset(a, 0, sizeof(char) * 1000);
		memset(b, 0, sizeof(char) * 1000);
		//将最终结果c反序成正确的顺序
		turn(c, a);
		//看成一个新的加数,再次循环
		strcpy(a, c);
	}
	cout << c;
	return 0;
}

2.二叉树的最长路径

给定一棵二叉树T,求T中的最长路径的长度,并输出此路径上各结点的值。若有多条最长路径,输出最右侧的那条。

输入格式:

第1行,1个整数n,表示二叉树有n个结点, 1≤n≤100000.

第2行,2n+1个整数,用空格分隔,表示T的扩展先根序列, -1表示空指针,结点用编号1到n表示。

输出格式:

第1行,1个整数length,length表示T中的最长路径的长度。

第2行,length+1个整数,用空格分隔,表示最右侧的最长路径。

 代码长度限制-16 KB

时间限制-100 ms

内存限制-5 MB

完整代码:

扩展先根遍历创建二叉树以及求深度算法课上都讲过,比较基础一定要会。

输出具体路径时类比先根遍历,依据“根右左”顺序遍历,当找到一个叶子结点的时候判断高度与最大高度是否相同即可

题目有一定难度,代码还要多看

#include<iostream>
#include<cstdio>
using namespace std;

//树的结点
typedef struct node
{
    int data;
    struct node* left;
    struct node* right;
} TreeNode, * Tree;

//扩展先根序列建立二叉树
void creat(Tree& T)
{
    int ch;
    cin >> ch;
    if (ch == -1) T = NULL;
    else
    {
        T = new TreeNode;
        T->data = ch;
        //递归建树,算法之前写过直接copy
        creat(T->left);
        creat(T->right);
    }
}

//求树的深度,算法之前写过
int depth(Tree T)
{
    if (T == NULL)
        return 0;
    else
    {
        //递归,一个树的深度就是左右子树中大的一个+1
        int m = depth(T->left);
        int n = depth(T->right);
        if (m > n) return (m + 1);
        else return (n + 1);
    }
}
//输出最长路径
//大概思路是向先根遍历一样根右左遍历并将结点存在数组中,如果有一条恰好是最长路径则输出
void printpath(Tree T, int path[], int pathlen, int d)
{
    int i;
    if (T != NULL) 
    {
        //记录当前路径,一棵树的根节点
        path[pathlen] = T->data;
        //递归出口,只要找到叶子结点向上只有一条路,判断是否最长即可
        if (T->left == NULL && T->right == NULL) 
        {
            if (pathlen == d - 1)
            {
                for (i = 0; i <= pathlen; i++)
                {
                    if (i == 0)
                        cout << path[i];
                    else cout << " " << path[i];
                }
                cout << endl;
                exit(0);
            }
        }
        //递归,一路向右找到最深处再往上遍历,右子树没有再找左子树
        else 
        {
            printpath(T->right, path, pathlen + 1, d);
            printpath(T->left, path, pathlen + 1, d);
        }
    }
}

int main()
{
    int n;
    cin >> n;
    Tree T;
    //扩展先根序列建树
    creat(T);
    //求长度,先求深度然后长度是深度-1
    int d = depth(T);
    cout << d - 1 << endl;
    //寻找最长路径保存在数组中,pathlen记录下标
    int path[100001];
    int pathlen = 0;
    printpath(T, path, pathlen, d);

}

3. 稀疏矩阵之和

矩阵A和B都是稀疏矩阵。请计算矩阵的和A+B.如果A、B不能做和,输出“Illegal!”

输入格式:

矩阵的输入采用三元组表示,先A后B。对每个矩阵:

第1行,3个整数N、M、t,用空格分隔,分别表示矩阵的行数、列数和非0数据项数,10≤N、M≤50000,t≤min(N,M).

第2至t+1行,每行3个整数r、c、v,用空格分隔,表示矩阵r行c列的位置是非0数据项v, v在32位有符号整型范围内。三元组默认按行列排序。

输出格式:

矩阵A+B,采用三元组表示,默认按行列排序,非零项也在32位有符号整型范围内。

 代码长度限制-16 KB

时间限制-100 ms

内存限制-10 MB

完整代码:

不算特别难,情况比较复杂要仔细一点写

#include<iostream>
#include<stdio.h>
#include<malloc.h>
#define MAX 60000
using namespace std;

//矩阵中的一个整数信息
struct node {
	int r, c, v;
};
//一个矩阵
typedef struct {
	int rs, cs, num;
	struct node data[MAX];
}Matrix;

//求两矩阵之和
void MatAdd(Matrix a, Matrix b, Matrix* c) {
	int i = 0, j = 0;
	int temp;
	int va, vb, vc;
	//矩阵行数或列数不相等
	if (a.rs != b.rs || a.cs != b.cs) { printf("Illegal!"); exit(0); }
	//结果矩阵的行数和列数与A,B相同
	c->rs = a.rs;
	c->cs = a.cs;
	c->num = 0;
	while (i < a.num && j < b.num)
	{
		//同一位置的数作和
		if (a.data[i].r == b.data[j].r && a.data[i].c == b.data[j].c)
		{
			temp = a.data[i].v + b.data[j].v;
			if (temp)
			{
				c->data[c->num].r = a.data[i].r;
				c->data[c->num].c = a.data[i].c;
				c->data[c->num++].v = temp;
			}
			i++; j++;
		}
		//A比B位置小
		if ((a.data[i].r == b.data[j].r && a.data[i].c < b.data[j].c) || a.data[i].r < b.data[j].r)
		{
			c->data[c->num].r = a.data[i].r;
			c->data[c->num].c = a.data[i].c;
			c->data[c->num++].v = a.data[i].v;
			i++;
		}
		//A比B位置大
		if ((a.data[i].r == b.data[j].r && a.data[i].c > b.data[j].c) || a.data[i].r > b.data[j].r)
		{
			c->data[c->num].r = b.data[j].r;
			c->data[c->num].c = b.data[j].c;
			c->data[c->num++].v = b.data[j].v;
			j++;
		}
	}
	while (i < a.num)
	{
		c->data[c->num].r = a.data[i].r;
		c->data[c->num].c = a.data[i].c;
		c->data[c->num++].v = a.data[i].v;
		i++;
	}
	while (j < b.num)
	{
		c->data[c->num].r = b.data[j].r;
		c->data[c->num].c = b.data[j].c;
		c->data[c->num++].v = b.data[j].v;
		j++;
	}
}

int main() {
	//保存三个矩阵,分别是A,B,A+B的和C
	Matrix* a, * b, * c;
	a = (Matrix*)malloc(sizeof(Matrix));
	b = (Matrix*)malloc(sizeof(Matrix));
	c = (Matrix*)malloc(sizeof(Matrix));
	scanf("%d%d%d", &a->rs, &a->cs, &a->num);
	int i;
	for (i = 0; i < a->num; i++)
	{
		scanf("%d%d%d", &a->data[i].r, &a->data[i].c, &a->data[i].v);
	}
	scanf("%d%d%d", &b->rs, &b->cs, &b->num);
	for (i = 0; i < b->num; i++)
	{
		scanf("%d%d%d", &b->data[i].r, &b->data[i].c, &b->data[i].v);
	}
	//求和
	MatAdd(*a, *b, c);
	//输出最终结果
	printf("%d %d %d\n", c->rs, c->cs, c->num);
	for (i = 0; i < c->num; i++)
	{
		printf("%d %d %d\n", c->data[i].r, c->data[i].c, c->data[i].v);
	}
	return 0;
}

4. 序列调度

有一个N个数的序列A:1,2,……,N。有一个后进先出容器D,容器的容量为C。如果给出一个由1到N组成的序列,那么可否由A使用容器D的插入和删除操作得到。

输入格式:

第1行,2个整数T和C,空格分隔,分别表示询问的组数和容器的容量,1≤T≤10,1≤C≤N。

第2到T+1行,每行的第1个整数N,表示序列的元素数,1≤N≤10000。接下来N个整数,表示询问的序列。

输出格式:

T行。若第i组的序列能得到,第i行输出Yes;否则,第i行输出No,1≤i≤T。

 代码长度限制-16 KB

时间限制-100 ms

内存限制-10 MB

完整代码:

先入栈,如果栈顶元素小于序列元素->下一个进栈继续比较;如果栈顶元素等于序列元素->弹栈,下一个进栈继续比较;如果栈顶元素大于序列元素->输出No

#include<iostream>
#include<stack>
#define maxsize 10005
using namespace std;

int main()
{
	int flag;
	stack<int>t;
	int data[maxsize];
	int T, C, N, x;
	int k,i,j;
	//组数和容器容量
	cin >> T >> C;
	for (k = 1; k <= T; k++)
	{
		//每一组的元素个数与序列
		cin >> N;
		flag = 1;
		for (i = 1; i <= N; i++)
			cin >> data[i];
		i = 1;
		//清空栈,方便下一轮循环时使用
		while (!t.empty()) 
			t.pop();
		for (j = 1; j <= N; j++)
		{
			//栈顶元素等于序列,弹出后继续
			if (!t.empty() && t.top() == data[j])
			{
				t.pop();
				continue;
			}
			//栈顶元素大于序列
			if (i > data[j]) {
				flag = 0;
				printf("No\n");
				break;
			}
			//栈顶元素小于序列一直进栈
			for (; i <= data[j]; i++) t.push(i);
			if (t.size() > C) {
				flag = 0;
				printf("No\n");
				break;
			}
			//最后必将i=data[j],要弹出
			t.pop();
		}
		if (flag)
			printf("Yes\n");
	}
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值