目录
二叉树基本操作
求先序排列
Description
给出一棵二叉树的中序与后序排列。求出它的先序排列。(约定树结点用不同的大写字母表示,且二叉树的节点个数 ≤8≤8)。
Input
共两行,均为大写字母组成的字符串,表示一棵二叉树的中序与后序排列。
Output
共一行一个字符串,表示一棵二叉树的先序。
Sample 1
Inputcopy | Outputcopy |
---|---|
BADC BDCA | ABCD |
#include<cstdio>
#include<cstring>
#include<bits/stdc++.h>
using namespace std;
void bef(string mid,string aft){
if(mid.size()>0){
char c=aft[aft.size()-1];cout<<c;//二叉树的根
int k=mid.find(c);//结点,从此分为左右
bef(mid.substr(0,k),aft.substr(0,k));//leftson
bef(mid.substr(k+1),aft.substr(k,mid.size()-k-1));//rightson
//s.substr(pos, len)pos到len个字符的拷贝,不加参数会默认拷贝整个s
}
}
int main(){
string mid,aft;
cin>>mid>>aft;
bef(mid,aft);cout<<endl;
return 0;
}
substr函数
substr(size_type _Off = 0,size_type _Count = npos)
形式 : s.substr(pos, len)
返回值: string,包含s中从pos开始的len个字符的拷贝(pos的默认值是0,len的默认值是s.size() - pos,即不加参数会默认拷贝整个s)
异常 :若pos的值超过了string的大小,则substr函数会抛出一个out_of_range异常;若pos+n的值超过了string的大小,则substr会调整n的值,只拷贝到string的末尾
C++中substr()函数用法详解_c++ substr_哦啦哦啦!的博客-CSDN博客
新二叉树
Description
输入一串二叉树,输出其前序遍历。
Input
第一行为二叉树的节点数 n。(1≤n≤26)
后面 �n 行,每一个字母为节点,后两个字母分别为其左右儿子。特别地,数据保证第一行读入的节点必为根节点。
空节点用 *
表示
Output
二叉树的前序遍历。
Sample 1
Inputcopy | Outputcopy |
---|---|
6 abc bdi cj* d** i** j** | abdicj |
#include<cstdio>
#include<cstring>
#include<bits/stdc++.h>
using namespace std;
struct node{
char l,r;
}t[130];//以字符的ACSII码作下标 所以数组开大点
void after(char s){
if(s=='*')return;
cout<<s;
after(t[s].l );//找leftson的先递归完
after(t[s].r );//再找rightson
}
int main(){
int n;cin>>n;
char s,c;
cin>>s;
cin>>t[s].l;
cin>>t[s].r;
for(int i=1;i<n;i++){
cin>>c;
cin>>t[c].l ;
cin>>t[c].r ;
}
after(s);
return 0;
}
FBI树
Description
我们可以把由 0 和 1 组成的字符串分为三类:全 0 串称为 B 串,全 1 串称为 I 串,既含 0 又含 1 的串则称为 F 串。
FBI 树是一种二叉树,它的结点类型也包括 F 结点,B 结点和 I 结点三种。由一个长度为 2N 的 01 串 S 可以构造出一棵 FBI 树 T,递归的构造方法如下:
- T 的根结点为 R,其类型与串 S 的类型相同;
- 若串 S 的长度大于 1,将串 S 从中间分开,分为等长的左右子串 S1 和 S2;由左子串 S1 构造 R 的左子树 T1,由右子串 S2 构造 R 的右子树 T2。
现在给定一个长度为 2^N 的 01 串,请用上述构造方法构造出一棵 FBI 树,并输出它的后序遍历序列。
Input
第一行是一个整数 N(0≤N≤10),
第二行是一个长度为 2N 的 01 串。
Output
一个字符串,即 FBI 树的后序遍历序列。
Sample 1
Inputcopy | Outputcopy |
---|---|
3 10001011 | IBFBBBFIBFIIIFF |
#include<stdio.h>
char A[1025];
void work(int low, int up)
{
int mid = (low+up)/2;
if (low!=up){//分成左右长度相同两子串
work(low, mid);
work(mid+1,up);
}//递归出口左右相等 到达树根
int i,a=0,b=0;
for (i=low;i<=up;i++)
if (A[i]=='0') a++;
else b++;//全1
if (a&&b) printf("F");//有1有0 F
else if (a) printf("B");//全0 B
else printf("I");//全1 I
}
int main()
{
int n;
scanf("%d", &n);
scanf("%s", A+1);//从 A[1] 开始输入
work(1, 1<<n);//1的二进制从右向左移动n位 即为2的n次方
return 0;
}
堆
Description
给定一个数列,初始为空,请支持下面三种操作:
- 给定一个整数 x,请将 x 加入到数列中。
- 输出数列中最小的数。
- 删除数列中最小的数(如果有多个数最小,只删除 1 个)。
Input
第一行是一个整数,表示操作的次数 n。
接下来 n 行,每行表示一次操作。每行首先有一个整数 op 表示操作类型。
- 若 op=1,则后面有一个整数 x,表示要将 x 加入数列。
- 若 op=2,则表示要求输出数列中的最小数。
- 若 op=3,则表示删除数列中的最小数。如果有多个数最小,只删除 1 个。
Output
对于每个操作 22,输出一行一个整数表示答案。
Sample 1
Inputcopy | Outputcopy |
---|---|
5 1 2 1 5 2 3 2 | 2 5 |
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int h[N];
int len=0;
void push(int x){ //插入数字
h[++len]=x;
int i=len; //重新排序
while(i>1&&h[i]<h[i/2]){
swap(h[i],h[i/2]);
i/=2;//上浮
}
}
void pop(){ //删除数字
h[1]=h[len];
len--;
int i=1;
while(2*i<=len){
int s=2*i;
if(s<len&&h[s+1]<h[s]){
s++;
}
if(h[s]<h[i]){
swap(h[s],h[i]);
i=s;
}
else {
break;
}
}
}
int main(){
int n;cin>>n;
int op,x;
while(n--){
cin>>op;
if(op==1){
cin>>x;
push(x);
}
else if(op==2){
cout<<h[1]<<endl;//数组经过我们的排列,小数上浮,只要输出h[1]即可
}
else{
pop();
}
}
}
合并果子
Description
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。
每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过 n−1 次合并之后, 就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。
因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为 1 ,并且已知果子的种类 数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。
例如有 33 种果子,数目依次为 1 , 2 , 9 。可以先将 1 、 2 堆合并,新堆数目为 3 ,耗费体力为 33 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12 ,耗费体力为 12 。所以多多总共耗费体力 3+12=15 。可以证明 1515 为最小的体力耗费值。
Input
共两行。
第一行是一个整数 n(1≤n≤10000) ,表示果子的种类数。
第二行包含 n 个整数,用空格分隔,第 i 个整数 ai(1≤ai≤20000) 是第 i 种果子的数目。
Output
一个整数,也就是最小的体力耗费值。输入数据保证这个值小于 231 。
Sample 1
Inputcopy | Outputcopy |
---|---|
3 1 2 9 | 15 |
#include<cstdio>
#include<cstring>
#include<bits/stdc++.h>
using namespace std;
int n,x;
int sum;
priority_queue<int,vector<int>,greater<int> >q;//自动从大到小排序
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=0;i<n;i++){
cin>>x;
q.push(x);//插入队列
}
while(q.size()>=2){
int a,b;
a=q.top();q.pop();
b=q.top();q.pop();
q.push(a+b); //合并至一个
sum+=a+b;
}
cout<<sum<<endl;//总耗费体力
return 0;
}
中位数
Description
给定一个长度为 N 的非负整数序列 A,对于前奇数项求中位数。
Input
第一行一个正整数 N。
第二行 N 个正整数 A1…N。
Output
共 ⌊2N+1⌋ 行,第 i 行为 A1…2i−1 的中位数。
Sample 1
Inputcopy | Outputcopy |
---|---|
7 1 3 5 7 9 11 6 | 1 3 5 6 |
Sample 2
Inputcopy | Outputcopy |
---|---|
7 3 1 5 9 8 7 6 | 3 3 5 6 |
HINT
直接用排序会时间超限,用优先队列存两组数,一组比现中位数大,一组比现中位数小。
#include<cstdio>
#include<cstring>
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+1;
int a[N];
int n,mid;
priority_queue<int,vector<int> > q1;//大根堆
priority_queue<int,vector<int>,greater<int> > q2;//小根堆
int main(){
cin>>n;
scanf("%d",&a[1]);
mid=a[1];
cout<<mid<<endl;
for(int i=2;i<=n;i++){
scanf("%d",&a[i]);
if(a[i]>mid) q2.push(a[i]);
else q1.push(a[i]);
if(i%2==1){//奇数
while(q1.size()!=q2.size()){
if(q1.size()>q2.size()){
q2.push(mid);
mid=q1.top();
q1.pop();
}
else{
q1.push(mid);
mid=q2.top();
q2.pop();
}
}
cout<<mid<<endl;
}
}
return 0;
}