JLU数据结构荣誉课——第三次上机实验

JLU数据结构荣誉课——第三次上机实验

7-1 二叉树最长路径 (100 分)

在这里插入图片描述

题目解析

求二叉树的最右,最长路径。

分析

递归建树,再用递归遍历。但两次递归可能会导致超时,需要小心处理。

代码实现如下

#include <bits/stdc++.h>
using namespace std;
struct Node
{
    int item;
    Node* left;
    Node* right;
};
int n,i,len;
queue<int> q;
Node* creat(Node* a)
{
    int m;
    scanf("%d",&m);
    if(i==n)return a;
    if(m==-1)
    {
        a=NULL;
        return a;
    }
    else
    {
        a=(Node*)malloc(sizeof(Node));
        a->item=m;
        a->left=creat(a->left);
        a->right=creat(a->right);
        i++;
    }
    return a;
}
int High(Node* a)
{
    if(a==NULL)return -1;
    else
    {
        return max(High(a->left),High(a->right))+1;
    }
}
int main()
{
    Node *root,*t;
    scanf("%d",&n);
    root=creat(t);
    Node* p0;
    p0=root;
    while(p0!=NULL)
    {
        q.push(p0->item);
        len++;
        if(p0->left==NULL||p0->left!=0&&p0->right!=0&&High(p0->left)<=High(p0->right))
            p0=p0->right;
        else
            p0=p0->left;
    }
    printf("%d\n",len-1);
    while(!q.empty())
    {
        printf("%d",q.front());
        q.pop();
        if(!q.empty())
        printf(" ");
    }
}

7-2 森林的层次遍历 (100 分)

在这里插入图片描述

题目解析

将森林的先根遍历转化成层次遍历。

分析

第一种方法,想用循环建树,在建树的时候保存每个节点的层数,然后按照节点的层数进行排序,但过程有亿点曲折。
开始排序的时候选择了系统的快排,忽略了快排的不稳定性,但离谱的点就在于,当数据小于18个是系统的快排调用的是插入排序,这就导致我自己写进去的样例都能正常进行,但pta上只有10分。。。在几经曲折,发现快排不稳定后,改用了计数排序,但是由于建树和排序都需要空间,导致了空间超限,最后一个样例过不去。
最后借鉴了昊原的方法,发现了其实不用真正地建树,算出每个节点地层数就行了。

代码实现如下

#include <bits/stdc++.h>
int a[100001],b[100001],Cs[100001];
char c[100001];
int main()
{
    int n,cs=0,i;
    scanf("%d",&n);
    for(i=0;i<n;i++)
    {
        scanf(" %c",&c[i]);
    }
    for(i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
    }
    for(i=0;i<n;i++)
    {
        b[i]=cs;
        if(cs!=0)Cs[cs-1]--;
        if(a[i]!=0)
            Cs[cs++]=a[i];
        while(Cs[cs-1]==0&&cs>0)
        {
            cs--;
        }
    }
    int k=n;
    printf("%c",c[0]);
    while(k>2)
    {
        for(i=1;i<n;i++)
        {
            if(b[i]==0)
            {
                printf(" %c",c[i]);
                k--;
            }
            b[i]--;
        }
    }
}

7-3 纸带切割 (100 分)

在这里插入图片描述

题目解析

这是一个典型地哈夫曼树。

分析

虽然是哈夫曼树,但不用真正地建立一棵哈夫曼树,只需要用到哈夫曼算法。强行用基本排序会超时,用单点队列优化即可。

代码实现如下

#include<stdio.h>
#include<malloc.h>
#include <bits/stdc++.h>
using namespace std;
priority_queue<long long int,vector<long long int>, greater<long long int> > q;
int num2[100002];
int main()
{
    int n,i,t;
    scanf("%d",&n);
    for(i=0;i<n;i++)
        {
           scanf("%d",&t);
           q.push(t);
        }
 //   if(n==1)printf("%d\n%d",)
    int j=0;
    i=0;
    for(i=0;i<n-1;i++)
    {
        int a1,a2;
        a1=q.top();
        q.pop();
        a2=q.top();
        q.pop();
        q.push(a1+a2);
        num2[i]=a1+a2;
    }
    long long int sum=0;
    for(i=0;i<n-1;i++)
        {
            sum+=num2[i];
        }
        printf("%lld\n",sum);
    for(i=n-2;i>=0;i--)
    {
        if(i!=0)
        printf("%d ",num2[i]);
        else
            printf("%d",num2[i]);
    }
}

7-4 序列乘积 (100 分)

在这里插入图片描述

分析

这道题想要拿一部分分很简单 上机的时候因为前面的题用了太多的时间,到这道题时只有不到十分钟了。。。当时直接用了纯暴力的方法,过了三个样例。
讲题的时候听了炫神的方法,因为输入数据是递增的,所以我们可以维护一个大小为 n 的优先队列,初始时储存二维数组的第一列,输出了某个元素就将其后一个入队。

代码实现如下

#include <bits/stdc++.h>
using namespace std;
int a[100001],b[100001],c[100001];
struct MM
{
    int hang,lie,item;
    bool operator<(const MM& a)const
    {
        return item > a.item;
    }
};
priority_queue<MM> q;
int main()
{
    int n,i,j=0,t;
    scanf("%d",&n);
    for(i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
    }
    for(i=0;i<n;i++)
    {
        scanf("%d",&b[i]);
    }
    for(i=0;i<n;i++)
    {
        MM m;
        m.hang=i;
        m.lie=0;
        m.item=a[i]*b[0];
        q.push(m);
    }
    for(i=0;i<n;i++)
    {
        MM m;
        m=q.top();
        q.pop();
        c[j++]=m.item;
        m.lie+=1;
        m.item=a[m.hang]*b[m.lie];
        q.push(m);
    }
    printf("%d",c[0]);
    for(i=1;i<n;i++)
    {
        printf(" %d",c[i]);
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值