数据结构第六次上机实验

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 <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
void fanxu(char num0[],char cpy0[])
{
	int len,i,j;
	len=strlen(num0);
	for(i=0,j=len-1;i<len;i++,j--)
	{
		cpy0[i]=num0[j];
	}
	cpy0[len]='\0';
	strcpy(num0,cpy0);
}
char a[1000],b[1000],c[1000];

int main()
{
	
	int i,j,len_a,len_b,bwei=0,jwei=0;
	int num;
	scanf("%d",&num);
	cin>>a;
    if(num==1) 
    {
      cout<<a; 
	  return 0;}
	for(int k=1;k<num;k++)
	{
		cin>>b;	
		fanxu(a,c);
		fanxu(b,c);
		len_a=strlen(a);len_b=strlen(b);
		for(i=0;i<len_a&&i<len_b;i++)
		{
			bwei=jwei+(a[i]-'0')+(b[i]-'0');
			if(bwei>=10) 
			{
				jwei=1;
				bwei-=10;
			}
			else jwei=0;
			c[i]=bwei+'0';
		}
		if(len_a>len_b)
		{
			for(;i<len_a;i++)
			{
				bwei=a[i]+jwei-'0';
				if(bwei>=10) 
				{
					jwei=1;
					bwei-=10;
				}
				else jwei=0;
				c[i]=bwei+'0';
			}
		} 
		if(len_b>len_a)
		{
			for(;i<len_b;i++)
			{
				bwei=b[i]+jwei-'0';
				if(bwei>=10) 
				{
					jwei=1;
					bwei-=10;
				}
				else jwei=0;
				c[i]=bwei+'0';			
			}	
		} 
		if(jwei==1) c[i++]='1'; 
		jwei=0;
		c[i]='\0';
        memset(a,0,sizeof(char)*1000);
        memset(b,0,sizeof(char)*1000);
		fanxu(c,a);
		strcpy(a,c);
	}
	cout<<c;
	return 0;
}

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

思路

1.求出两点的最近公共祖先,在每个结点内部都保存一个当前结点的深度,这样,最近公共祖先深度减去出发点等于上行距离,减去终点深度等于下行距离。
2.注意两点中一点为另一点的祖先的情况。

代码

#include <stdio.h>
#include <iostream>
#include <deque>
#include <string.h>
using namespace std;
struct tree{
	int num;
	int tall;
	struct tree *father;
	struct tree *left;
	struct tree *right;
};
typedef struct tree tree;
int ff,ee,up,down;
tree t[100005];
int main()
{
	int num;
	cin>>num;
	for(int i=1;i<num;i++)
	{
		int f,s;
		cin>>f>>s;
		if(t[f].left==NULL) t[f].left=&t[s];
		else t[f].right=&t[s];
		t[s].father=&t[f];
		t[s].tall=t[f].tall+1;
		
	}
	cin>>ff>>ee;
	tree *f1=&t[ff],*f2=&t[ee];
	while(f1!=f2)
	{
		if(f1->tall>f2->tall)
		{
			f1=f1->father;
		}
		else f2=f2->father;
	}
	int all=0;
	if(f1==&t[ff]) all=-(f1->tall-t[ee].tall)*2;
	else if(f2==&t[ee]) all=-(f1->tall-t[ff].tall)*3;
	else all=-(f1->tall-t[ff].tall)*3-(f1->tall-t[ee].tall)*2;
	cout<<all;
}

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.假设从节点1到节点n有多条最短路,那么本题求的是其中边最大值最小的最短路,课通过最小生成树算法和单元最短路算法求得。
(1)kruskal算法:当最小生成树产生的时候,节点1和节点n必然是联通的,根据kruskal算法的选边的原则,那么最小生成树内包含的从1到n的路的边的最大值必然是最小的。
(2)dijistal算法:基础的dijistal算法求出的从1到n的路是总长度最小的路,而不能保证边的最大值在所有的路中最小,所以将dis数组内的值保存为这条边所在的路中的最大权值,每次找最小的权值做更新。

代码

#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 500005;//点数最大值
const int INF = 100005;
int n, m, cnt;//n个点,m条边
typedef struct Edge
{
	int u, to, w, next;//起点,终点,边权,同起点的上一条边的编号
} Edge;
Edge edge[2 * maxn];//边集
int head[maxn];//head[i],表示以i为起点的第一条边在边集数组的位置(编号)
void init()//初始化
{
	for (int i = 0; i <= n; i++) head[i] = -1;
	cnt = 0;
}
void add_edge(int u, int v, int w)//加边,u起点,v终点,w边权
{
	edge[cnt].u = u;
	edge[cnt].to = v; //终点
	edge[cnt].w = w; //权值
	edge[cnt].next = head[u];//以u为起点上一条边的编号,也就是与这个边起点相同的上一条边的编号
	head[u] = cnt++;//更新以u为起点上一条边的编号
}
//kruskal算法
int father[INF];
int FIND(int x)
{
	while (father[x] > 0) x = father[x];
	return x;
}
void MAKE_SET(int x)
{
	father[x] = 0;
}
void UNION(int x, int y)
{
	int fx = FIND(x), fy = FIND(y);
	if (fx == fy) return;
	if (father[fx] < father[fy]) father[fy] = fx;
	else {
		if (father[fx] == father[fy]) father[fy]--;
		father[fx] = fy;
	}
}
struct cmp
{
	bool operator()(Edge a, Edge b)
	{
		return a.w <b.w;
	}
};
bool dmp(Edge a, Edge b)
{
	return a.w <b.w;
}
priority_queue<	Edge, vector<Edge>, cmp> min_t;
void KRU()
{
	for (int i = 1; i <= m; i++) MAKE_SET(i);
	sort(edge, edge + m, dmp);
	for (int i = 0, j = 0; i < m; i++)
	{
		int v = edge[i].to;
		int u = edge[i].u;
		if (FIND(v) != FIND(u))
		{
			UNION(v, u);
			min_t.push(edge[i]);
		}
		if (FIND(1)==FIND(n)) break;
	}
}
int main()
{
	cin >> n >> m;
	int u, v, w = 0;
	init();//初始化
	for (int i = 1; i <= m; i++)//输入m条边
	{
		cin >> u >> v>>w;
		add_edge(u, v, w);
		//add_edge(v, u, w);
	}
	KRU();
	if(!min_t.empty())cout << min_t.top().w;
    else cout<<"0";
	return 0;

}

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

思路:

keypoint: 对于所有数字的反转的处理,引入一个标记,将所有的数按照标记存入两个数组,一个为当前状态为+时,另一个为当前状态为-时。
有两种基本思路:
1.单调队列:对整体区间求最值满足单调队列的使用。
2.使用两个单调队列,一种近似单调队列的处理方法。

法2代码

#include <iostream>
#include <stdio.h>
#include <queue>
#include <vector>
using namespace std;
long long zhen[10000005], fu[10000005];
int flag = 1;
struct cmp {
	bool operator()(int a, int b)
	{
		return zhen[a] < zhen[b];
	}
};
struct dmp {
	bool operator()(int a, int b)
	{
		return fu[a] < fu[b];
	}
};
priority_queue<int , vector<int>, cmp> bq;
priority_queue<int, vector<int>, dmp> sq;
int main()
{
	int num, n, sign = 0, l = 0, e = 0;
	char ope;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
        getchar();
		scanf("%c",&ope);
		if (ope == 'I')
		{
			scanf("%d", &num);
			zhen[e] = flag * num;
			fu[e] = -flag * num;
			sq.push(e);
			bq.push(e);
			e++;
		}
		else if (ope == 'D')
		{
			if (l < e) l++;
		}
		else if (ope == 'R')
		{
			flag = -flag;
		}
		else if (ope == 'M')
		{
			
				if (flag == 1)
				{
					while (!bq.empty()&&bq.top() < l) bq.pop();
					if(!bq.empty()) printf("%d\n", zhen[bq.top()]);
				}
				else
				{
					while (!sq.empty()&&sq.top() < l) sq.pop();
					if(!sq.empty()) printf("%d\n", fu[sq.top()]);
				}
			}


	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于《数据结构与算法第五版》的上机实验指导,我很抱歉我不能提供具体的指导内容。但是,我可以给你一些关于数据结构与算法实验的一般指导,希望对你有所帮助。 1. 确定实验目标:首先,你需要明确每个实验的目标和要求。这包括实验要解决的问题、要使用的数据结构和算法、预期的实验结果等。 2. 设计合适的数据结构:根据实验要求,选择合适的数据结构来解决问题。例如,可以使用链表、树、图等数据结构来组织数据,以便进相应的操作。 3. 实现算法:根据实验要求和选择的数据结构,编写相应的算法来解决问题。这包括对数据结构插入、删除、查找等操作的具体实现。 4. 编写测试代码:为了验证你的实现是否正确,编写测试代码来模拟各种情况下的输入和输出。通过测试代码,可以检查你的算法是否满足预期要求,并找出可能存在的问题。 5. 运和调试:运你的程序并进调试。如果发现程序有错误或不符合预期结果,可以通过调试工具和打印中间结果等方式来找出问题所在,并进修复。 6. 总结和分析结果:对实验结果进总结和分析。比较实验结果与预期结果的差异,思考实验中遇到的问题以及可能的改进方法。 总之,进数据结构与算法实验需要你具备一定的编程能力和理解能力。同时,根据实验要求,选择合适的数据结构和算法,并进适当的测试和调试。希望以上指导对你有所帮助!如果你有具体的问题,欢迎继续提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值