数据结构第六次上机实验解题报告

数据结构第六次上机实验解题报告

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
在这里插入图片描述
解答:根据题意是一个常规的大整数加法题目,先用字符串读入,再将字符串转化为整数数组,注意整数的反向存储(进位时比较方便),然后逐位相加处理进位即可。

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
在这里插入图片描述
解答:根据题意是一个寻找公共祖先的问题(但当时并没有看出来),把他转化为了一个图,若a与b之间有边,则设置双向边,对上行边赋权值为3,对下行边赋权值为2,对构建的图进行SPFA算法计算最短路径,因为SPFA算法时间复杂度只有O(kE),性能比较好。
具体代码实现:

#include<bits/stdc++.h>
using namespace std;
vector<pair<int,int> > e[100001];
int visited[100001];
int dist[100001];
int n;
queue<int>que;
void SPFA(int v);
int main()
{
	int i;
	scanf("%d",&n);
    int u,v;
	for(i=0;i<n-1;i++)
	{
		scanf("%d%d",&u,&v);
		e[u].push_back({v,2});
		e[v].push_back({u,3});
	}	
	scanf("%d%d",&u,&v);
	SPFA(u);
	cout<<dist[v];
}
void SPFA(int v)
{
	int i;
	for(i=1;i<=n;i++)dist[i]=1000000;
	dist[v]=0;
	int u;
	que.push(v);
	visited[0]=1;
	while(!que.empty())
	{
		u=que.front();
		que.pop();
		visited[u]=0;
		for(i=0;i<e[u].size();i++)
		{
			pair<int,int> vw=e[u][i];
			int h=vw.first,o=vw.second;
		if(dist[u]+o<dist[h]) 
			{
			dist[h]=dist[u]+o;
			if(!visited[h])
			{
				que.push(h);
				visited[h]=1;
			}	
		}
		}	
	}
}

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
在这里插入图片描述

解答:
根据题意首先要满足从1结点到n结点有路径,且路径上的最大权值是所有路径中最小的,如果把所有路径都找出来,再对所有最大路径进行比较,太消耗时间,所以可以使用SPFA算法,把其中的dist保存每条路径上的最大权值中的最小权值,其实可以转化为最小生成树问题,使用prim算法和Kruskal算法也可以解决。
具体代码实现:

#include<bits/stdc++.h>
using namespace std;
vector<pair<int,int> > e[100001];
int visited[100001];
int dist[100001];
int n;
queue<int>que;
void SPFA(int v);
int main()
{
	int i,m,c;
	cin>>n>>m;
    int u,v;
	for(i=0;i<m;i++)
	{
		cin>>u>>v>>c;
		e[u].push_back({v,c});
		e[v].push_back({u,c});
	}	
	//for(i=1;i<=n;i++)p[i].push_back(-1);
	//for(i=1;i<=n;i++)
	//visited[i]=0;
	SPFA(1);
	cout<<dist[n];
}
void SPFA(int v)
{
	int i,max=0;
	for(i=1;i<=n;i++)dist[i]=100000;
	dist[v]=0;
	int u;
	que.push(v);
	visited[v]=1;
	while(!que.empty())
	{
		u=que.front();
		que.pop();
		visited[u]=0;
		for(i=0;i<e[u].size();i++)
		{
			max=dist[u];
			pair<int,int> vw=e[u][i];
			int h=vw.first,o=vw.second;
			if(max<o)max=o;
		if(max<dist[h]) 
			{
			dist[h]=max;
			if(!visited[h])
			{
				que.push(h);
				visited[h]=1;
			}	
		}
		}	
	}
}

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

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

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

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

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

取最大值操作(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

在这里插入图片描述
解答:根据题意4个操作中插入和删除操作都是O(1)的,但全部取反和取最大值,暴力来做将会是O(n)的,对于取反操作,这里设置一个标记flag取反时反转标记,其他操作根据flag的不同而变化即可,避免了逐个取反,对于取最大值,可以维护两个双端队列,因为有取反操作,则需要维护一个存最大值的队列,维护一个存最小值的队列。
具体代码实现:

#include<bits/stdc++.h>
using namespace std;
deque<int> max0,min0;
int fro,rear;
int a[1000000];
int main()
{
	int i,temp,j,flag=0;
	char k;
	int m;
	cin>>m;
	for(i=0;i<m;i++)
	{
		scanf("\n%c",&k);
		if(k=='I')
		{
			rear++;
			scanf("%d",&temp);
			if(flag==0)
			{
			a[rear]=temp;	
			}
			else
			{
			a[rear]=-temp;	
			}
			temp=a[rear];
			while(!max0.empty()&&a[max0.back()]>=temp)
			{
			max0.pop_back();	
			}
			max0.push_back(rear);
			while(!min0.empty()&&a[min0.back()]<=temp)
			{
			min0.pop_back();
			}
			min0.push_back(rear);
		}
		else if(k=='D')
		{
			if(fro<rear)
			{
				fro++;
				while(!max0.empty()&&max0.front()<=fro)
				{
				max0.pop_front();
				}
				while(!min0.empty()&&min0.front()<=fro)
				{
				min0.pop_front();
				}
			}
		}
		else if(k=='R')
		{
			if(flag==0)flag=1;else flag=0;
		}
		else if(k=='M')
		{
			if(rear!=fro)
			{
			if(flag==1)
			{
				printf("%d\n",-a[max0.front()]);
				}
			else
			{
				printf("%d\n",a[min0.front()]);
				}	
			}
			
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值