数据结构第六次上机实验解题报告
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()]);
}
}
}
}
}