洛谷官方题单【数据结构1-2】二叉树

1.P4715 【深基16.例1】淘汰赛
解题思路:分上下半区选取亚军,则前半区最强的与后半区最强的相比较,弱的就是亚军

#include <iostream>
using namespace std;
int x[128];
int main(){
	int n,sum=1;
	cin >> n;
	for(int i=0;i<n;i++){
		sum*=2;
	}
	for(int i=0;i<sum;i++){
		cin >> x[i];
	}
	int m1=x[0],m2=x[sum/2],n1=1,n2=sum/2+1;
	for(int i=0;i<sum/2;i++){
		if(x[i]>m1){
			m1=x[i];
			n1=i+1;
		}
	}
	for(int i=sum/2;i<sum;i++){
		if(x[i]>m2){
			m2=x[i];
			n2=i+1;
		}
	}
	if(m1<m2){
		cout << n1;
	}else{
		cout << n2;
	}
	return 0;
} 

2.P4913 【深基16.例3】二叉树深度
解题思路:用结构体数组存储树,从根节点开始深度优先搜索即DFS.

#include <iostream>
using namespace std;
struct node{
	int l;
	int r;
};
node x[100001];
int nmax=0;
int dfs(int now,int num){
	if(num>nmax){
		nmax=num;
	}
	if(x[now].l!=0){
		dfs(x[now].l,num+1);
	}
	if(x[now].r!=0){
		dfs(x[now].r,num+1);
	}
}
int main(){
	int n;
	cin >> n;
	node now;
	for(int i=1;i<=n;i++){
		cin >> x[i].l >> x[i].r;
	}
	dfs(1,1);
	cout << nmax;
	return 0;
}

3.P1827 \USACO3.4\美国血统 American Heritage
解题思路:前序遍历的第一个字符为根节点,在中序遍历查找根节点记为pos。中序遍历中pos左边为左子树,右边为右子树。则左子树的中序遍历为0开始的pos个字符,前序遍历为1开始的pos个字符。右子树的中序遍历为pos+1开始的剩余字符,右子树的前序遍历同理。递归左子树,右子树,最后输出当前节点。

#include <iostream>
#include <string>
using namespace std;
void dg(string &s1,string &s2){
	if(s2.empty()){
		return ;
	}
	string ss1,ss2,ss3,ss4;
	int pos=s1.find(s2[0]);
	ss1=s1.substr(0,pos);//取子串,从0开始的pos个子串
	ss2=s2.substr(1,pos);//取子串,从1开始的pos个子串
	ss3=s1.substr(pos+1);
	ss4=s2.substr(pos+1);
	dg(ss1,ss2);
	dg(ss3,ss4);
	cout << s2[0];//先左后右最后中间
}
int main(){
	string s1,s2;
	cin >> s1 >> s2;
	dg(s1,s2);
	return 0;
}

4.P5076 【深基16.例7】普通二叉树(简化版)
解题思路:使用stl中的的multiset和lower_bound,upper_bound函数.
multiset是一个允许出现重复数值,底层用二叉搜索树实现的集合。第一个操作使用lower_bound()查找当前数值的第一次出现的位置pos,然后从s.begin()开始迭代,直到迭代到pos得到排名。第二个操作就是从begin()开始迭代,直到查询到排名。第三个和第四个操作类似,lower_bound()如果结果是s.begin(),则无前驱,upper_bound()如果结果是s.end(),则无后驱。

#include <iostream> 
#include <set>
#include <algorithm>
using namespace std;
int main(){
	multiset<int> s;
	int n,op,num;
	cin >> n;
	for(int i=0;i<n;i++){
		multiset<int>:: iterator it,now;
		cin >> op >> num;
		if(op==1){
			int j=1;
			it=s.lower_bound(num);
			now=s.begin();
			while(now!=it){
				j++;
				now++;
			}
			cout << j << endl;
		}else if(op==2){
			now=s.begin();
			for(int i=0;i<num-1;i++){
				now++;
			}
			cout << *now << endl;
		}else if(op==3){
			it=s.lower_bound(num);
			if(it==s.begin()){
				cout << -0x7fffffff <<endl;
			}else{
				it--;
				cout << *it << endl;
			}
		}else if(op==4){
			it=s.upper_bound(num);
			if(it==s.end()){
				cout << 0x7fffffff<<endl;
			}else{
				cout << *(it) << endl;
			}
		}else if(op==5){
			s.insert(num);
		}
	}
	return 0;
}

5.P1364 医院设置
解题思路:将这个题看成一个节点最多会有三个节点与之相连的图即可,从编号1的节点开始依次bfs遍历,记录最小值即可。

#include <iostream>
#include <queue>
using namespace std;
struct node{
	int l;
	int r;
	int weight;
	int head;
	int no;
};
node x[101];
int cnt=-1,visit[101],nsum=0;
int bfs(int now){
	nsum=0;
	for(int i=1;i<=100;i++){
		visit[i]=0;
	}
	queue<node> q;
	x[now].no=0;
	q.push(x[now]);
	visit[now]=1;
	while(!q.empty()){
		node l=q.front();
		nsum+=l.no*l.weight;
		if(l.head!=0 && visit[l.head]==0){
			x[l.head].no=l.no+1;
			visit[l.head]=1;
			q.push(x[l.head]);
		}
		if(l.l!=0 && visit[l.l]==0){
			x[l.l].no=l.no+1;
			visit[l.l]=1;
			q.push(x[l.l]);
		}
		if(l.r!=0 && visit[l.r]==0){
			x[l.r].no=l.no+1;
			 visit[l.r]=1;
			q.push(x[l.r]);
		}
		q.pop();
	}
	if(cnt==-1){
		cnt=nsum;
	}else if(cnt>nsum){
		cnt=nsum;
	}
}
int main(){
	int n;
	cin >> n;
	node now;
	for(int i=1;i<=n;i++){
		x[i].head=0;
	}
	for(int i=1;i<=n;i++){
		cin >> x[i].weight >> x[i].l >> x[i].r;
		x[x[i].l].head=i;
		x[x[i].r].head=i;
	}
	for(int i=1;i<=n;i++){
		bfs(i);
	}
	cout << cnt;
	return 0;
}

6.P1229 遍历问题
解题思路:什么样的节点才会导致知道前序遍历和后序遍历不知道二叉树到底是什么样子呢?答案是只有一个子节点的节点。无论是这个子节点是左节点还是右节点,他们的前序遍历和后序遍历都是一样的。显然我们同时可以得知一个节点如果只有一个子节点会导致二叉树的可能翻倍。
那么还剩最后一个问题,我怎么知道一个节点只有一个子节点呢?如果A是B的双亲节点,且A只有B这样一个节点,那么先序遍历A在B的前面,而后序遍历B在A的前面。此时所有的问题都已经解决了。

有一说一,这道题代码不难,思路还是比较难想的

#include <iostream>
#include <string>
using namespace std;
int main(){
	int cnt=1;
	string s1,s2;
	cin >> s1 >> s2;
	for(int i=0;i<s1.length()-1;i++){
		for(int j=i;j<s2.length();j++){
			if(s1[i]==s2[j] && s1[i+1]==s2[j-1]){
				cnt*=2;	
			}
		}
	}
	cout << cnt;
	return 0;
} 

7.P1305 新二叉树
解题思路:这道题的坑点在于你并不知道树的根节点到底是哪一个,所以我使用了两个数组去得到这个根节点,have数组记录作为双亲结点的结点有哪些,visit数组记录作为子结点的结点有哪些,如果一个节点是双亲结点而不是子结点,那么这个结点就是二叉树的根节点。
最后来一发简单的前序遍历即可。

#include <iostream>
#include <cstdio>
using namespace std;
int have[26]={0},visit[26]={0};
struct node{
	int l;
	int r;
};
node x[26];
void pre(int f){
	printf("%c",f+'a');
	if(x[f].l!=-1){
		pre(x[f].l);
	}
	if(x[f].r!=-1){
		pre(x[f].r);
	}
}
int main(){
	int n,f;
	cin >> n;
	char now,l,r;
	for(int i=0;i<26;i++){
		x[i].l=-1;
		x[i].r=-1;
	}
	for(int i=0;i<n;i++){
		cin >> now >> l >> r;
		have[now-'a']=1;
		if(l!='*'){
			visit[l-'a']=1;
			x[now-'a'].l=l-'a';
		}
		if(r!='*'){
			visit[r-'a']=1;
			x[now-'a'].r=r-'a';
		}
	}
	for(int i=0;i<26;i++){
		if(have[i]==1 && visit[i]==0){
			f=i;
			break;
		}
	}
	pre(f);
	return 0;
}

8.P1030 [NOIP2001 普及组] 求先序排列
解题思路:与第三题类似

#include <iostream>
using namespace std;
void dg(string &s1,string &s2){
	if(s2.empty()){
		return ;
	}
	string ss1,ss2,ss3,ss4;
	int pos;
	pos=s1.find(s2[s2.length()-1]);
	ss1=s1.substr(0,pos);
	ss2=s2.substr(0,pos);
	ss3=s1.substr(pos+1);
	ss4=s2.substr(pos,ss3.length());
	cout << s2[s2.length()-1];
	dg(ss1,ss2);
	dg(ss3,ss4);
}
int main(){
	string s1,s2;
	cin >> s1 >> s2;
	dg(s1,s2);
	return 0;
}

未完待续。。。。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值