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]);
}
}