第六次上机实验

7-1 高精度数加法 (100 分)

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

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

输入格式:

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

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

输出格式:

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

输入样例:

在这里给出一组输入。例如:

3
12345678910
12345678910
12345678910

输出样例:

在这里给出相应的输出。例如:

37037036730

 思路:

首先以字符串的形式输入这些数字,再把每个字符转换为数字储存在数组中,两个数相加,和的位数最多是这两个数的最大位数加一,然后两个数相加(相同位数的数字),这里要用到进位器,还要把最高位的零(如果有)清除掉

#include<bits/stdc++.h>
using namespace std;
char ch1[10000], ch2[10000];
int a[10000], b[10000], c[10000];
int n, L;
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n;
	if (n == 1) {
		cin >> ch1;
		cout << ch1;
		return 0;
	}
	int i, j, jinwei = 0;
	cin >> ch1;
	for (i = 2; i <= n; i++) {
		cin >> ch2;
		int x1, x2;
		x1 = strlen(ch1);
		for (j = 0; j < x1; j++) {
			a[j] = ch1[x1 - j - 1] - '0';
		}
		x2 = strlen(ch2);
		for (j = 0; j < x2; j++) {
			b[j] = ch2[x2 - j - 1] - '0';
		}
		if (x1 >= x2) {
			L = x1 + 1;
		}
		else {
			L = x2 + 1;
		}
		for (j = 0; j < L; j++) {
			c[j] = a[j] + b[j] + jinwei;
			if (c[j] >= 10) {
				jinwei = 1;
			}
			else
				jinwei = 0;
			c[j] = c[j] % 10;
		}
		for (j = L - 1; j >= 0; j--) {
			if (c[j] == 0 && L > 1) {
				L--;
			}
			else {
				break;
			}
		}
		for (j = 0; j < L; j++) {
			ch1[L - j - 1] = c[j] + '0';
		}
		for (j = 0; j < L; j++) {
			a[j] = 0;
			b[j] = 0;
		}
	}
	for(int i=L-1;i>=0;i--){
		cout << c[i];
	}
	cout << endl;
}

 

7-2 二叉树加权距离 (100 分)

二叉树结点间的一种加权距离定义为:上行方向的变数×3 +下行方向的边数×2 。上行方向是指由结点向根的方向,下行方向是指与由根向叶结点方向。 给定一棵二叉树T及两个结点u和v,试求u到v的加权距离。

输入格式:

第1行,1个整数N,表示二叉树的结点数,(1≤N≤100000)。

随后若干行,每行两个整数a和b,用空格分隔,表示结点a到结点b有一条边,a、b是结点的编号,1≤a、b≤N;根结点编号为1,边从根向叶结点方向。

最后1行,两个整数u和v,用空格分隔,表示所查询的两个结点的编号,1≤u、v≤N。

输出格式:

1行,1个整数,表示查询的加权距离。

输入样例:

在这里给出一组输入。例如:

5
1 2
2 3
1 4
4 5
3 4

输出样例:

在这里给出相应的输出。例如:

8

思路: 

这道题可以建树也可以建图,树其实就是一种特殊的图,这里采用的是建二叉树。每个节点还增加了父节点,求权的过程是,比较两个节点的深度,更深的指向其父节点,直到相遇,最后的结果为起点与相遇点的深度差的绝对值乘以三加上终点与相遇点的深度差的绝对值乘以2

#include<bits/stdc++.h>
using namespace std;
struct point {
	int pre = -1;
	int left = -1, right = -1;
	int depth = 0;
};
int n;
struct point a[100000];
int main() {
	cin >> n;
	int i, x, y, u, v, num;
	for (i = 0; i < n-1; i++) {
		cin >> x >> y;
		if (a[x].left == -1) {
			a[x].left = y;
		}
		else {
			a[x].right = y;
		}
		a[y].pre = x;
		a[y].depth = a[x].depth + 1;
	}
	cin >> u >> v;
	x = u;//这里不写成x=a[u].pre,因为可能就是求这个点到本身的权
	y = v;
	while (x != y) {
		if (a[x].depth > a[y].depth) {
			x = a[x].pre;
		}
		else {
			y = a[y].pre;
		}
	}
	num = (a[u].depth - a[x].depth) * 3 + (a[v].depth - a[x].depth) * 2;
	cout << num;
}

 

7-3 修轻轨 (100 分)

长春市有n个交通枢纽,计划在1号枢纽到n号枢纽之间修建一条轻轨。轻轨由多段隧道组成,候选隧道有m段。每段候选隧道只能由一个公司施工,施工天数对各家公司一致。有n家施工公司,每家公司同时最多只能修建一条候选隧道。所有公司可以同时开始施工。请评估:修建这条轻轨最少要多少天。。

输入格式:

第1行,两个整数n和m,用空格分隔,分别表示交通枢纽的数量和候选隧道的数量,1 ≤ n ≤ 100000,1 ≤ m ≤ 200000。

第2行到第m+1行,每行三个整数a、b、c,用空格分隔,表示枢纽a和枢纽b之间可以修建一条双向隧道,施工时间为c天,1 ≤ a, b ≤ n,1 ≤ c ≤ 1000000。

输出格式:

输出一行,包含一个整数,表示最少施工天数。

输入样例:

在这里给出一组输入。例如:

6 6
1 2 4
2 3 4
3 6 7
1 4 2
4 5 5
5 6 6

输出样例:

在这里给出相应的输出。例如:

6

 思路:

这道题是最小生成树的问题,但是不同于普通的最小生成树的问题的是它不一定要连接所有的点,所以这里的结束条件就变成了find(1)==find(n)。最后的结果即为最后一条路的权

#include<bits/stdc++.h>
using namespace std;
int pre[100001];
struct edge {
	int start;
	int final;
	int num;
};
struct edge a[200002];
int cost, n, m;
class com {
public:
	bool operator()(edge& x, edge& y) {
		return x.num < y.num;
	}
};
int find(int x) {
	if (pre[x] == x) {
		return x;
	}
	return pre[x]=find(pre[x]);
}
void Union(int x, int y) {
	int x1 = find(x);
	int y1 = find(y);
	if (x1 != y1) {
		pre[y1] = x1;
	}
}
void kruskal() {
	sort(a, a + m, com());
	int i;
	for (i = 1; i <= n; i++) {
		pre[i] = i;
	}
	for (i = 0; i < m; i++) {
		if (find(a[i].start) != find(a[i].final)) {
			cost = a[i].num;
			Union(a[i].start, a[i].final);
		}
		if (find(1) == find(n)) {
			break;
		}
	}
}
int main() {
	cin >> n >> m;
	for (int i = 0; i < m; i++) {
		cin >> a[i].start >> a[i].final >> a[i].num;
	}
	kruskal();
	cout << cost;
}

 

7-4 数据结构设计I (100 分)

小唐正在学习数据结构。他尝试应用数据结构理论处理数据。最近,他接到一个任务,要求维护一个动态数据表,并支持如下操作:

  1. 插入操作(I):从表的一端插入一个整数。

  2. 删除操作(D):从表的另一端删除一个整数。

  3. 取反操作(R):把当前表中的所有整数都变成相反数。

  4. 取最大值操作(M):取当前表中的最大值。

    如何高效实现这个动态数据结构呢?

输入格式:

第1行,包含1个整数M,代表操作的个数, 2≤M≤1000000。

第2到M+1行,每行包含1个操作。每个操作以一个字符开头,可以是I、D、R、M。如果是I操作,格式如下:I x, x代表插入的整数,-10000000≤x≤10000000。 。

输出格式:

若干行,每行1个整数,对应M操作的返回值。如果M和D操作时队列为空,忽略对应操作。

输入样例:

在这里给出一组输入。例如:

6
I 6
R
I 2
M
D
M

输出样例:

在这里给出相应的输出。例如:

2
2

思路: 

 之前用的是暴力,毫无疑问超时了,所以这里要维护两个双端队列,当flag为1,插入的是数的相反数。在单调递减的队列q1中队头保存最大值,在单调递增的队列q2中队头保存最小值

#include<bits/stdc++.h>
using namespace std;
int a[2000002];
int x, y;  
int flag = 0;
deque<int> q1;
deque<int> q2;
void I() {
	x++;
	cin >> a[x];
	if (flag == 1) {
		a[x] = -a[x];
	}
	while (!q1.empty() && a[q1.back()] < a[x]) {
		q1.pop_back();
	}
	q1.push_back(x);
	while (!q2.empty() && a[q2.back()] > a[x]) {
		q2.pop_back();
	}
	q2.push_back(x);
}
void D() {
	if (y < x) {
		y++;
		while (!q1.empty() && q1.front() <= y) {
			q1.pop_front();
		}
		while (!q2.empty() && q2.front() <= y) {
			q2.pop_front();
		}
	}
}
void M() {
	if (y < x) {
		if (!flag) {
			cout<<a[q1.front()]<<"\n";
		}
		else {
			cout<<-a[q2.front()]<<"\n";
		}
	}
}
int main() {
	std::ios::sync_with_stdio(0);
	cin.tie(0);
	int m, i;
	cin >> m;
	char ch;
	for (i = 0; i < m; i++) {
		cin >> ch;
		if (ch == 'I') {
			I();
		}
		else if (ch == 'D') {
			D();
		}
		else if (ch == 'R') {
			flag = (flag + 1) % 2;
		}
		else if (ch == 'M') {
			M();
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值