数据结构第六次实验报告

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

思路:高精度加法正常是要逆序存储,因为这样会方便进位操作,但是我在考试的时候没有这样做(忘了这件事了),我就每次产生进位就进行一次  if(a[0]!='0') strcpy(a+1,a);  操作,向后移动一位,这题时间要求不是很严格,这样写可以通过。

#include<bits/stdc++.h>
using namespace std;
const int INF=1e9+7;
typedef long long ll;
char a[1000010],b[110];
int n;
int main()
{
    cin>>n;
    n--;
    scanf("%s",a+1);
    while(n--)
    {
        scanf("%s",b+1);
        int lena=strlen(a+1);
        int lenb=strlen(b+1);
        int len=max(lena,lenb);
        char cc=0;
        while(len>0)
        {
            if(lena>0&&lenb>0) a[len]=a[lena]-'0'+b[lenb]+cc;
            else if(lena<=0&&lenb>0) a[len]=b[lenb]+cc;
            else if(lena>0&&lenb<=0) a[len]=a[lena]+cc;
            if(a[len]>'9') {a[len]-=10;cc=1;}
            else cc=0;
            lena--;len--;lenb--;
        }
        a[0]=cc+'0';
        if(a[0]!='0') strcpy(a+1,a);
    }
    printf("%s",a+1);
    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

思路:这道题的做法比较多,我当时是把二叉树每个节点的指针域都指向自己的父亲节点,查询时不断循环找根节点并保存距离。要注意的是可能一个节点在向上寻找的过程中找到了另一个节点,这时循环应该结束。另外,如果要查询的节点可能有根节点,而向上和向下的距离是不等的,应该加上一个特判,但其实这道题的测试样例并没有出现这种情况。

#include<bits/stdc++.h>
using namespace std;
const int INF=1e9+7;
typedef long long ll;
int n,count1,count2,countt;
int pnode[100001];
int main()
{
    cin>>n;
    int x,y;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        pnode[y]=x;
    }
    scanf("%d%d",&x,&y);
    if(x==1||y==1)
    {
    	if(x==1)
    	{
    		while(y!=1){
       		y=pnode[y];
        	count1++;
    		}
    		cout<<count1*2;
    		exit(0);
		}
		if(y==1)
		{
			while(x!=1){
       		x=pnode[x];
        	count1++;
    		}
    		cout<<count1*2;
    		exit(0);
		}
	}
    while(y!=1&&y!=x){
        y=pnode[y];
        count1++;
    }
    if(y==x)
    {
    	cout<<count1*2;
    	exit(0);
	}
    while(x!=1&&y!=x)
    {
        x=pnode[x];
        count2++;
    }
    if(y==x&&x!=1)
    {
    	cout<<count2*3;
    	exit(0);
	}
    countt=count1*2+count2*3;
    cout<<countt;
    return 0;
}

    还有一种能想到的方法就是最短路的方法,在读入时存两个节点的距离,父亲到儿子存2,儿子到父亲存3;然后用dijkstra、SPFA等方法跑一个最短路即可。

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

思路:这道题很容易看出来是最小生成树的思想,采用Kruskal方法,不同的是这道题需要把循环结束条件改为father[n]==father[1],另外虽然题目里说只有n个施工队,但是当father[n]==father[1]时,施工队是一定够用的(可以认为只有进行Union操作的道路才会进行施工,这样到循环结束,最多有n-1个施工队修了路)

#include<bits/stdc++.h>
using namespace std;
const int INF=1e9+7;
typedef long long ll;
int father[100001],m,n;
struct Node
{
    int x,y;
    ll cost;
    bool operator<(const Node& b)const
	{
		return cost < b.cost;
	}
}node[200011];
int Find(int v)
{
    if(father[v]==v) return v;
    return father[v]=Find(father[v]);
}
void Union(int x,int y)
{
    int a=Find(x);
    int b=Find(y);
    if(a!=b) father[a]=b;
}

int main()
{
    cin>>n>>m;
    
    for(int i=1;i<=n;i++) father[i]=i;
    int x,y;
    ll t;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%lld",&x,&y,&t);
        node[i].x=x;
        node[i].y=y;
        node[i].cost=t;
    }
    sort(node+1,node+m+1);
    ll minn=0;
    for(int i=1;;i++)
    {
        if(Find(node[i].x)!=Find(node[i].y))
        {
            Union(node[i].x,node[i].y);
            minn=node[i].cost;
        }
        if (Find(1) == Find(n))break;
    }
    cout<<minn;
    system("PAUSE");
    return 0;
}

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

思路:首先可以使用STL里面的multiset,不仅可以对数据进行排序,而且允许重复元素的存在。

不用multiset还可以使用单调队列的方法,首先声明一个数组模拟队列,用f和r来保存当前剩余元素的开始下标和结束下标。另外声明两个deque保存递增、递减两个单调队列。读入元素的时候,如果标记bj==1,就把这个元素本身存入数组,把下标存入两个单调队列,如果bj==-1,就把这个元素的相反数存入数组,把下标存入单调队列。删除操作:如果单调队列的头部小于f就弹出。          取最大元素:如果bj==1,就输出递减的单调队列的头部,否则输出递增的单调队列的头部的相反数。

#include<bits/stdc++.h>
using namespace std;
const int INF=1e9+7;
typedef long long ll;
int m;
int f,r;
int bj=1;
int num[1000001];
deque<int>dq1,dq2;      //1↑ ,2↓
int main()
{
    cin>>m;
    while(m--)
    {
        char c[2];
        scanf("%s",c);
        if(c[0]=='I')
        {
            r++;
            scanf("%d",&num[r]);
            if(bj==-1) num[r]=-num[r];
            while(!dq1.empty()&&num[dq1.back()]>=num[r]) dq1.pop_back();
            while(!dq2.empty()&&num[dq2.back()]<=num[r]) dq2.pop_back();
            dq1.push_back(r);dq2.push_back(r);
        }
        else if(c[0]=='D')
        {
            if(f<r)
            {
                f++;
                while(!dq1.empty()&&dq1.front()<=f) dq1.pop_front();
                while(!dq2.empty()&&dq2.front()<=f) dq2.pop_front();
            }
        }
        else if(c[0]=='M')
        {
            if(f<r)
            {
                if(bj==1) printf("%d\n",num[dq2.front()]);
                else printf("%d\n",-num[dq1.front()]);
            }
            
        }
        else if(c[0]=='R')
        {
            bj=-bj;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值