二叉树部分的题目

二叉树的存储

P4715 【深基16.例1】淘汰赛

#include <bits/stdc++.h>
using namespace std;
int n, id, value[260], win[260], total, ans;
void dfs(int cur){
	if(cur>total-1){
		return;
	}
	int leftid=2*cur;
	int rightid=2*cur+1;
	dfs(leftid);
	dfs(rightid);
	if(value[leftid]>value[rightid]){
		value[cur]=value[leftid];
		win[cur]=win[leftid];
	}
	else{
		value[cur]=value[rightid];
		win[cur]=win[rightid];
	}
}
int main()
{
	scanf("%d", &n);
	total=1<<n;
	/*
		       1
		  2            3
       4      5     6      7
     8   9  10 11 12 13  14  15  
     */
	for(int i=0; i<total; ++i){
		id=total+i;
		scanf("%d", &value[id]);
		win[id]=i+1;
	}
	dfs(1);
	if(value[2]>value[3]){
		ans=win[3];
	}
	else{
		ans=win[2];
	}
	printf("%d", ans);
	return 0;
}

P4913 【深基16.例3】二叉树深度

#include<bits/stdc++.h>
using namespace std;
int n, a[1000010][3], l, r, ans;
void dfs(int curdeep, int x)
{
    if(a[x][1]==0 && a[x][2]==0){   //无左子树和右子树
        ans=max(ans, curdeep);
        return;
    }
    if(a[x][1]!=0){     //有左子树
        dfs(curdeep+1, a[x][1]);
    }
    if(a[x][2]!=0){     //有右子树
        dfs(curdeep+1, a[x][2]);
    }
}
int main()
{
    scanf("%d", &n);
    for(int i=1; i<=n; ++i){
        scanf("%d %d", &l, &r);
        a[i][1]=l;
        a[i][2]=r;
    }
    dfs(1, 1);    
    printf("%d", ans);
    return 0;
}

P5076 【深基16.例7】普通二叉树(简化版)

#include <bits/stdc++.h>
using namespace std;
int q, x, opt, n, site, a[10001], b[10001];
int main()
{
	scanf("%d", &q);
	while(q--){
		scanf("%d", &opt);
		scanf("%d", &x);
		if(opt==1){	//查询x的排名, 坑点:不用管x在不在里面, 只用找出有多少个比x小即可 
			int cnt=0;
			for(int i=1; i<=n; ++i){
				if(a[i]<x){
					cnt++;
				}
			} 
			printf("%d\n", cnt+1);
		}
		else if(opt==2){	//查询排名为x的数, 坑点:不用去重 
			printf("%d\n", a[x]);
		}
		else if(opt==3){	//求x的前驱,未找到前驱则输出-2147483647
			//坑点:不用管x在不在里面, 只用找到比x小的数里的最大值 
			int pre=-2147483647; 
			for(int i=1; i<=n; ++i){
				if(a[i]<x){
					pre=max(pre, a[i]);
				}
				else{
					break;
				}
			}
			printf("%d\n", pre);
		} 
		else if(opt==4){	//求x的后继,若未找到后继则输出 2147483647
			//坑点:不用管x在不在里面, 只用找到比x大的数里的最小值
			bool flag=false; 
			for(int i=1; i<=n; ++i){
				if(a[i]>x){
					flag=true;
					printf("%d\n", a[i]);
					break;
				}
			}
			if(!flag){	//没有后继 
				printf("2147483647\n"); 
			}
		}
		else if(opt==5){	//插入一个数 x
			//找到在哪个位置插入, 然后插入
			if(n==0){	//插入第一个数时 
				n++;
				a[n]=x;
			}
			else if(x<=a[1]){	//在开头插入 
				for(int i=n; i>=1; --i){
					a[i+1]=a[i];
				}
				a[1]=x;
				n++;
			} 
			else if(x>=a[n]){	//在末尾插入 
				n++;
				a[n]=x;
			} 
			else{	//在中间插入 
				for(int i=1; i<=n-1; ++i){
					if(x>=a[i] && x<=a[i+1]){
						site=i+1; 
					} 
				} 
				for(int i=n; i>=site; --i){
					a[i+1]=a[i];
				}
				a[site]=x;
				n++;
			} 
		}
	}
	return 0;
} 

二叉树的三种遍历方法

P1030 [NOIP2001 普及组] 求先序排列

#include <bits/stdc++.h>
using namespace std;
string in_order, post_order;
int len;
//中序 从l1到r1,后序从l2到r2 
void dfs(int l1, int r1, int l2, int r2)
{
	int flag;
	//剪枝,已经没有节点了,树为空 
	if(l1>r1 || l2>r2)	return;	
	//后序遍历最后一个肯定是根节点 
	char root=post_order[r2];	
	//输出根结点 
	cout << root;
	//在中根遍历序列中找到根结点所在的位置,即可将结点分为左子树和右子树 
	for(int i=l1; i<=r1; ++i){
		if(in_order[i]==root){	//如果等于根 
			//flag记录的是中序遍历序列中,根结点的位置
			//在中根序列中,l1到flag-1的节点都属于左子树, 
			//flag+1到r1的节点都属于右子树 
			flag=i; 	 
			break; 
		}
	}
	//现在问题的关键是如何找出新的左子树的后序遍历序列、新的右子树的后续遍历序列
	//原来的后续遍历序列前面部分是左子树的后续序列,紧接着是右子树的后续序列,最后是跟结点
	//所以需要知道左子树有多少个结点。
	int left_node=flag-l1;
	//左子树有left_node个结点,则在后续遍历序列中,左子树的范围是从l2到l2+left_node-1 
	//紧接着就是右子树,则在后续遍历序列中,右子树的范围是从l2+left_node到r2-1 
	if(l1<flag)		//如果左边节点小于根结点的编号,说明有左子树,递归左子树 
		dfs(l1, flag-1, l2, l2+left_node-1);	
	if(flag<r1)		//如果右边节点大于根结点的编号,说明有右子树,递归右子树 
		dfs(flag+1, r1, l2+left_node, r2-1);	 
}
int main()
{
	cin >> in_order >> post_order;
	len=in_order.length();	//获取结点的数量 
	//中序从0到len-1, 后序从0到len-1 
	dfs(0, len-1, 0, len-1);
	return 0;
}

P1827 [USACO3.4]美国血统 American Heritage

先建树、后遍历

#include <bits/stdc++.h>
using namespace std;
char first;
int length;
string preorder, inorder;
//a[1]['C']='B', 表示'C'的左儿子是'B'
//a[2]['C']='G', 表示'C'的右儿子是'G'
map<char, char> a[3];	 
//s1 e1表示中序遍历序列的起终点下标
//s2 e2表示前序遍历序列的起终点下标 
//对树的中序遍历、先序遍历进行递归, 找出每个结点的左右儿子
void dfs(int s1, int e1, int s2, int e2)
{
	int rootid, leftnum=0;
	if(s1==e1 || s2==e2){	//*表示为空 
		a[1][inorder[s1]]=a[2][inorder[s1]]='*';
		a[1][preorder[s2]]=a[2][preorder[s2]]='*';
		return;
	}
	//找到根 
	char root=preorder[s2]; 
	//在中序遍历中找到根的下标
	for(int i=s1; i<=e1; ++i){
		leftnum++;	//左子树的结点数(包含root) 
		if(inorder[i]==root){
			rootid=i;
			break;
		}
	} 
	//root根有左儿子 
	if(rootid>s1){
		//记录左儿子 
		a[1][root]=preorder[s2+1]; 
		//对左子树的中序遍历、先序遍历进行递归, 找出每个结点的左右儿子
		dfs(s1, rootid-1, s2+1, s2+leftnum-1); 
	}
	else{
		a[1][root]='*';
	}
	//root根有右儿子 
	if(rootid<e1){
		//记录右儿子 
		a[2][root]=preorder[s2+leftnum];
		//对右子树的中序遍历、先序遍历进行递归, 找出每个结点的左右儿子 
		dfs(rootid+1, e1, s2+leftnum, e2);
	} 
	else{
		a[2][root]='*';
	}
}
void postorder(char cur)
{
	//没有左子树 
	if(a[1][cur]=='*'){		//*表示为空 
		//没有右子树 
		if(a[2][cur]=='*'){
			printf("%c", cur);
		}
		else{	//有右子树 
			//对右子树进行后序遍历 
			postorder(a[2][cur]);
			printf("%c", cur);	//输出根节点 
		} 
	} 
	else{	//有左子树 
		//对左子树进行后序遍历 
		postorder(a[1][cur]);
		//没有右子树 
		if(a[2][cur]=='*'){
			printf("%c", cur);	//输出根节点 
		}
		else{	//有右子树 
			//对右子树进行后序遍历 
			postorder(a[2][cur]);
			printf("%c", cur);	//输出根节点 
		} 
	}
}
int main()
{
	cin >> inorder >> preorder;
	first=preorder[0];	//二叉树的根节点 
	length=inorder.length();
	dfs(0, length-1, 0, length-1);	//注意length-1 
	postorder(first);	//递归求后序遍历 
	return 0;
}

P1364 医院设置

#include <bits/stdc++.h>
using namespace std;
int n, dis[110], cur, ans=2e9, u, v, w[110], a[110][4];
bool vis[110];
//id结点到医院的距离为x 
void dfs(int id, int x)
{
	//遍历id结点的左儿子、右儿子、父节点 
	for(int i=1; i<=3; ++i){
		//如果有, 并且没被遍历过 
		if(a[id][i]!=0 && !vis[a[id][i]]){
			//标记为遍历过 
			vis[a[id][i]]=true;
			//更新最短距离 
			dis[a[id][i]]=x+1;
			//深搜 
			dfs(a[id][i], x+1);
		}
	} 
} 
int main()
{
	scanf("%d", &n);
	for(int i=1; i<=n; ++i){
		scanf("%d %d %d", &w[i], &u, &v);
		a[i][1]=u;	//i的左儿子 
		a[i][2]=v;	//i的右儿子
		a[u][3]=a[v][3]=i;	//u、v的父节点 
	}
	//枚举医院的所有可能 
	for(int i=1; i<=n; ++i){
		cur=0;
		memset(dis, 0, sizeof(dis));
		memset(vis, 0, sizeof(vis));
		//从医院出发, 去找其他n-1个点 
		vis[i]=true;
		dfs(i, 0);
		for(int j=1; j<=n; ++j){
			cur+=w[j]*dis[j];
		}
		ans=min(ans, cur);
	}
	printf("%d", ans);
	return 0;
}

P3884 [JLOI2009]二叉树问题

#include <bits/stdc++.h>
using namespace std;
int n, a[110][4], u, v, height=1, width, dis, num[110];
bool vis[110];
//找深度和宽度 
void dfsheight(int id, int x)
{
	for(int i=1; i<=2; ++i){
		if(a[id][i]!=0){	//有儿子 
			height=max(height, x+1);
			num[x+1]++;		//第x+1层节点数加一 
			dfsheight(a[id][i], x+1); 
		}
	}
} 
//找距离 
void dfsdis(int id, int x)
{
	if(id==v){
		dis=x;
		printf("%d\n%d\n%d", height, width, dis);
		exit(0);
	} 
	for(int i=1; i<=3; ++i){
		if(a[id][i]!=0 && !vis[a[id][i]]){	//有儿子, 并且没访问过 
			vis[a[id][i]]=true;
			if(i==3){	//向上 
				dfsdis(a[id][i], x+2); 
			}
			else{	//向下 
				dfsdis(a[id][i], x+1); 
			} 
		}
	}
} 
int main()
{
	scanf("%d", &n);
	for(int i=1; i<n; ++i){
		scanf("%d %d", &u, &v);
		if(a[u][1]==0){
			a[u][1]=v;	//u的左儿子是v 
		}
		else{
			a[u][2]=v;	//u的右儿子是v
		}
		a[v][3]=u;	//v的父节点是u 
	}
	scanf("%d %d", &u, &v);
	num[1]=1;
	dfsheight(1, 1);
	//找宽度 
	for(int i=1; i<=height; ++i){
		width=max(width, num[i]);
	}
	//找距离
	vis[u]=true;	//标记 
	dfsdis(u, 0); 
	return 0;
} 

P1229 遍历问题

#include <bits/stdc++.h>
using namespace std;
string s1, s2;
int length;
long long ans=1;
int main()
{
	cin >> s1 >> s2;
	reverse(s2.begin(), s2.end());
	length=s1.length();
	for(int i=0; i<length-1; ++i){
		for(int j=j=0; j<length-1; ++j){
			if(s1[i]==s2[j] && s1[i+1]==s2[j+1]){
				ans*=2;
			}
		}
	}
	printf("%lld", ans);
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ypeijasd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值