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

7-1 高精度数加法 

高精度数是指大大超出了标准数据类型能表示的范围的数,例如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>
#include <vector>
using namespace std;
const int INF=1<<30;
const int MAX=1e5+5;
typedef long long ll;

const int MAXN = 10000; //根据题目的最大值。+4为了防止A+B出现进位
char s1[MAXN] = {};//存储字符串
char s2[MAXN] = {};//存储字符串
int a[MAXN] = {};//存储加数A
int b[MAXN] = {};//存储加数B
int c[MAXN] = {};//存储和B

int main() {
    int n,len;
    scanf("%d",&n);
    if(n==1)//只有一个数字,不用算,直接输出
    {
        scanf("%s",s1);
        printf("%s\n",s1);
        return 0;
    }
    else
    {
    scanf("%s",s1);
        //将字符串写入到数组A中

    for(int kk=2;kk<=n;kk++)
    {
    scanf("%s",s2);//读入字符串
    //将字符串写入到数组B中
    int len1 = strlen(s1);
    for (int i=0; i<len1; i++) {
        //倒序写入
       a[i] = s1[len1-i-1] - '0';
    }
    int len2 = strlen(s2);
    for (int i=0; i<len2; i++) {
        //倒序写入
        b[i] = s2[len2-i-1] - '0';
    }

    //模拟竖式加法
    int jw=0;//进位
    len = max(len1, len2)+1;//注意因为最高位可能出现进位
    for (int i=0; i<len; i++) {
        c[i] = a[i] + b[i] + jw;//当前加数A位数据+加数B位位数据+上一位的进位
        jw = c[i] / 10;//本次加法是否存在进位
        c[i] %= 10;//只能保存 0 ~ 9 的数据
    }

    //删除前导零
   for (int i=len-1; i>=0; i--) {
        //因为我们是从索引 0 开始,所以最高位是保存在 len-1
        if (0==c[i] && len>1) {
            //注意要有 len>1 这个条件。考虑特殊情况,加法结果为 00,我们实际要输出 0。
            len--;
        } else {
            //第一个不是零的最高位,结束删除
            break;
        }
    }
    for (int i = 0; i < len; i++) {
         s1[len-1-i] = c[i] + '0';
    }
    for (int i = 0; i < len; i++) {
         a[i] = 0;
         b[i] = 0;
    }
}
    //逆序打印输出
    for (int i=len-1; i>=0; i--) {
        printf("%d", c[i]);
    }
    printf("\n");
}
return 0;
}

7-2 二叉树加权距离 

二叉树结点间的一种加权距离定义为:上行方向的变数×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、在建树的结构体中,我们只需要存放父亲结点,以及结点的深度,这里的深度指的是由跟出发,向下走的边数,默认跟的深度为1,在输入时,每次都要将儿子结点,在父亲结点深度的基础上加1。

2、计算距离是,考虑几种情况:

第一、两个结点是同一个结点。

第二、第一个结点的父亲是第二个结点。

第三、第二个结点的父亲是第一个结点。

第四、第一个结点的深度比第二个结点的深度大。

第五、第二个结点的深度比第一个结点的深度大。

第六、两个结点的在同一个深度。

完整代码:

#include<bits/stdc++.h>
#include<cstdio>
#include<stdlib.h>
#include<stack>
using namespace std;
const int MAX=100005;
struct node
{
    int fa,deep;
}tree[MAX];
int n;
int main(){
int i,u,v;
scanf("%d",&n);
tree[1].deep=1;
for(i=1;i<n;i++)
{
    scanf("%d%d",&u,&v);
    tree[v].fa=u;
    tree[v].deep=tree[u].deep+1;
}
scanf("%d%d",&u,&v);
if(u==v)
{
    printf("0");
    return 0;
}
int deep1=0,deep2=0;
while(tree[u].fa!=tree[v].fa)
{
    if(tree[u].fa==v)
    {
        cout<<(deep1+1)*3<<endl;
        return 0;
    }
    if(tree[v].fa==u)
    {
        cout<<(deep2+1)*2<<endl;
        return 0;
    }
    if(tree[u].deep>tree[v].deep)
    {
        deep1++;
        u=tree[u].fa;
    }
    if(tree[v].deep>tree[u].deep)
    {
        deep2++;
        v=tree[v].fa;
    }
    if(tree[u].deep==tree[v].deep&&tree[u].fa!=tree[v].fa)
    {
        deep1++;
        u=tree[u].fa;
        deep2++;
        v=tree[v].fa;
    }
}
cout<<(deep1+1)*3+(deep2+1)*2<<endl;
return 0;
}

7-3 修轻轨 

长春市有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

分析:

最小支撑树问题,用Kruskal算法,,只需要把1和n结点连通即可。因此循环退出条件就是find(1)==find(n),两个结点连通即可退出。施工公司可以同时施工,那么最长时间必然是最小支撑树上权值最大边,最后输出即可。

完整代码:

#include <bits/stdc++.h>
#include <vector>
using namespace std;
const int INF=1<<30;
const int MAX=200005;

struct edge
{
    int fr,to;
    long long w;
    bool operator<(const edge& b)const
    {
        return w<b.w;
    }
}a[MAX];

int fa[MAX];

int find(int x)
{
    if(fa[x]==x)
        return x;
    return fa[x]=find(fa[x]);
}

void merge(int x,int y)
{
    int a=find(x),b=find(y);
    if(a!=b)
        fa[a]=b;
}

int main()
{
    int n,m;
    long long ans=0;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d %lld",&a[i].fr,&a[i].to,&a[i].w);
    }
    sort(a+1,a+m+1);
    int cnt=0;
    for(int i=1;i<=m&&cnt!=n-1;i++)
    {
        if(find(a[i].fr)!=find(a[i].to))
        {
            cnt++;
            ans=a[i].w;
            merge(a[i].fr,a[i].to);
        }
        if(find(1)==find(n))break;
    }
    printf("%lld\n",ans);
    return 0;
}

7-4 数据结构设计I 

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

  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

分析:

一端插入,一端删除,考虑用双端队列。取反操作可以设置一个变量,每次取反它都进行非运算,最后根据这个值判断数字输出时是否应该取反。维护一个区间,用top表示头指针,fr表示尾指针。

完整代码:

#include<bits/stdc++.h>
using namespace std;
const int MAX= 1e6+5;
deque<int>maxx,minn;
int flag;
int a[MAX];
int top,fr;
int main()
{
    int m;
    scanf("%d",&m);
    char x[2];
    while(m--)
    {
        scanf("%s",x);
        if(x[0]=='I')
        {
            top++;
            scanf("%d",&a[top]);
            if(flag)
                a[top]=-a[top];
            int tmp=a[top];
            while(!maxx.empty()&&a[maxx.back()]>=tmp)maxx.pop_back();
            maxx.push_back(top);
            while(!minn.empty()&&a[minn.back()]<=tmp)minn.pop_back();
            minn.push_back(top);
        }
        else if(x[0]=='R')
        {
            flag^=1;
        }
        else if(x[0]=='D')
        {
            if(fr<top)
            {
                fr++;
                while(!maxx.empty()&&maxx.front()<=fr)maxx.pop_front();
                while(!minn.empty()&&minn.front()<=fr)minn.pop_front();
            }
        }
        else if(x[0]=='M')
        {
            if(fr<top)
            {
                if(flag)
                {
                    printf("%d\n",-a[maxx.front()]);
                }
                else
                {
                    printf("%d\n",a[minn.front()]);
                }
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值