2022.1.19(二叉树&并查集)

目录

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

题目描述

输入格式

输出格式

输入输出样例

说明/提示

思路

代码实现

 P1305 新二叉树

题目描述

输入格式

输出格式

输入输出样例

思路

代码实现

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

题目描述

输入格式

输出格式

输入输出样例

说明/提示

思路

代码实现 

 CF1416B Make Them Equal

题目描述

输入格式

输出格式

题意翻译

输入输出样例

思路

代码实现 


今天是致力于刷题的一天!!!

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

题目描述

农夫约翰非常认真地对待他的奶牛们的血统。然而他不是一个真正优秀的记帐员。他把他的奶牛 们的家谱作成二叉树,并且把二叉树以更线性的“树的中序遍历”和“树的前序遍历”的符号加以记录而 不是用图形的方法。

你的任务是在被给予奶牛家谱的“树中序遍历”和“树前序遍历”的符号后,创建奶牛家谱的“树的 后序遍历”的符号。每一头奶牛的姓名被译为一个唯一的字母。(你可能已经知道你可以在知道树的两 种遍历以后可以经常地重建这棵树。)显然,这里的树不会有多于 26 个的顶点。 这是在样例输入和 样例输出中的树的图形表达方式:

         C
         /  \
        /  \
       B    G
      / \  /
       A   D  H
        / \
       E   F

树的中序遍历是按照左子树,根,右子树的顺序访问节点。

树的前序遍历是按照根,左子树,右子树的顺序访问节点。

树的后序遍历是按照左子树,右子树,根的顺序访问节点。

输入格式

第一行: 树的中序遍历

第二行: 同样的树的前序遍历

输出格式

单独的一行表示该树的后序遍历。

输入输出样例

输入 #1复制

ABEDFCHG
CBADEFGH 

输出 #1复制

AEFDBHGC

说明/提示

题目翻译来自NOCOW。

USACO Training Section 3.4

思路

1、分别用字符串a,b存储前序和中序

2、设前序的起点与终点是a1,a2-1,中序的起点与终点是b1,b2-1

3、要知道前序遍历(根左右)的第一个结点是根节点

4、所以在中序遍历(左根右)中找到a1,记录其位置为k;k的左边就是左子树。右边就是右子树

5、用n,m存储左右子树结点个数

6、当n>0时即左子树结点个数不为零时,递归;

7、当m>0时即右子树结点个数不为零时,递归;

    int n=k-b1;//左子树的结点个数 
	int m=b2-(k+1);//右子树的节点个数
	if(n>0)
		fun(a1+1,a1+1+n,b1,b1+n);
	if(m>0)
		fun(a2-m,a2,k+1,k+1+m);	 
	cout<<a[a1];//最后输出根节点(后序遍历,左右根)

代码实现

#include<bits/stdc++.h>
using namespace std;
char a[100],b[100];
void fun(int a1,int a2,int b1,int b2)
{
	int k;//用于保存中序遍历中根节点的位置 
	for(int i=b1;i<b2;i++)
	{
		if(b[i]==a[a1])
		{
			k=i;
			break;
		}
	}
	int n=k-b1;//左子树的结点个数 
	int m=b2-(k+1);//右子树的节点个数
	if(n>0)
		fun(a1+1,a1+1+n,b1,b1+n);
	if(m>0)
		fun(a2-m,a2,k+1,k+1+m);	 
	cout<<a[a1];//最后输出根节点(后序遍历,左右根) 
	return; 
}
int main()
{
	int len;
	cin>>b>>a;
	len=strlen(a);
	//cout<<len;
	fun(0,len,0,len);
	return 0;
} 

 P1305 新二叉树

题目描述

输入一串二叉树,输出其前序遍历。

输入格式

第一行为二叉树的节点数 nn。(1 \leq n \leq 261≤n≤26)

后面 nn 行,每一个字母为节点,后两个字母分别为其左右儿子。

空节点用 * 表示

输出格式

二叉树的前序遍历。

输入输出样例

输入 #1复制

6
abc
bdi
cj*
d**
i**
j**

输出 #1复制

abdicj

思路

刚开始还想着建树,想了半天也觉得这真没法建呀,后来发现他是按顺序输入的二叉树,所以直接递归输出不就行了,还建什么树呀!!!

1、用二维数组把这n对父亲孩子存下来

2、按照前序遍历(根左右),递归输出

if(ch!='*')
	{
		cout<<ch;//输出根节点 
		for(int i=0;i<n;i++)
			if(a[i][0]==ch)
			{
				fun(a[i][1]);//递归,输出左节点 
				fun(a[i][2]);//递归,输出右节点 
			}
	}

代码实现

#include<bits/stdc++.h>
using namespace std;
int n;
char a[50][3]; 
void fun(char ch)
{
	if(ch!='*')
	{
		cout<<ch;//输出根节点 
		for(int i=0;i<n;i++)
			if(a[i][0]==ch)
			{
				fun(a[i][1]);//递归,输出左节点 
				fun(a[i][2]);//递归,输出右节点 
			}
	}
}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	for(int j=0;j<3;j++)
	{
		cin>>a[i][j];
	}
	fun(a[0][0]);
	return 0;
}

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

题目描述

给出一棵二叉树的中序与后序排列。求出它的先序排列。(约定树结点用不同的大写字母表示,长度\le 8≤8)。

输入格式

22行,均为大写字母组成的字符串,表示一棵二叉树的中序与后序排列。

输出格式

11行,表示一棵二叉树的先序。

输入输出样例

输入 #1复制

BADC
BDCA

输出 #1复制

ABCD

说明/提示

【题目来源】

NOIP 2001 普及组第三题

思路

这和第一个题思路不是一毛一样的!!!稍微改一下就好了

1、分别用字符串a,b存储后序和中序

2、设后序的起点与终点是a1,a2-1,中序的起点与终点是b1,b2-1

3、要知道后序遍历(左右根)的最后一个结点是根节点

4、所以在中序遍历(左根右)中找到a2-1,记录其位置为k;k的左边就是左子树。右边就是右子树

5、用n,m存储左右子树结点个数

6、当n>0时即左子树结点个数不为零时,递归;

7、当m>0时即右子树结点个数不为零时,递归;

    cout<<a[a2-1];//输出根节点(前序遍历,根左右)
	int k;//用于保存中序遍历中根节点的位置 
	for(int i=b1;i<b2;i++)
	{
		if(b[i]==a[a2-1])
		{
			k=i;
			break;
		}
	}
	int n=k-b1;//左子树的结点个数 
	int m=b2-(k+1);//右子树的节点个数
	if(n>0)
		fun(a1,a1+n,b1,b1+n);
	if(m>0)
		fun(a2-1-m,a2-1,k+1,k+1+m);	 

代码实现 

#include<bits/stdc++.h>
using namespace std;
char a[100],b[100];
void fun(int a1,int a2,int b1,int b2)
{
	cout<<a[a2-1];//输出根节点(前序遍历,根左右)
	int k;//用于保存中序遍历中根节点的位置 
	for(int i=b1;i<b2;i++)
	{
		if(b[i]==a[a2-1])
		{
			k=i;
			break;
		}
	}
	int n=k-b1;//左子树的结点个数 
	int m=b2-(k+1);//右子树的节点个数
	if(n>0)
		fun(a1,a1+n,b1,b1+n);
	if(m>0)
		fun(a2-1-m,a2-1,k+1,k+1+m);	  
	return; 
}
int main()
{
	int len;
	cin>>b>>a;
	len=strlen(b);
	//cout<<len;
	fun(0,len,0,len);
	return 0;
} 

P1177 【模板】快速排序

题目描述

利用快速排序算法将读入的 NN 个数从小到大排序后输出。

快速排序是信息学竞赛的必备算法之一。对于快速排序不是很了解的同学可以自行上网查询相关资料,掌握后独立完成。(C++ 选手请不要试图使用 STL,虽然你可以使用 sort 一遍过,但是你并没有掌握快速排序算法的精髓。)

输入格式

第 11 行为一个正整数 NN,第 22 行包含 NN 个空格隔开的正整数 a_iai​,为你需要进行排序的数,数据保证了 A_iAi​ 不超过 10^9109。

输出格式

将给定的 NN 个数从小到大输出,数之间空格隔开,行末换行且无空格。

输入输出样例

输入 #1复制

5
4 2 4 5 1

输出 #1复制

1 2 4 4 5

说明/提示

对于 20\%20% 的数据,有 N\leq 10^3N≤103;

对于 100\%100% 的数据,有 N\leq 10^5N≤105。

思路

本来想直接ac的,谁知道传统的快排后三个点都是tle

经过n小时对普通快排的优化(淦!还是不对!!),于是只能换个思路,真伤脑筋呀(这个的思路是学习一个大佬的)。

1、利用二分思想,

2、mid=a[(l+r)/2]; 

3、从左边找比中间数大的数,右边找比中间数小的数,进行交换;循环操作,直到i>j

4、进行递归

    if(l<j) 
		qsort(l,j);
    if(i<r) 
		qsort(i,r);

代码实现 

#include<bits/stdc++.h>
using namespace std;
int n,a[1000001];
void qsort(int l,int r)
{
    int mid=a[(l+r)/2]; 
    int i=l,j=r;
    do{
        while(a[i]<mid) i++;//左边比中间数大的数
        while(a[j]>mid) j--;//右边比中间数小的数
        if(i<=j)
        {
            swap(a[i],a[j]);//交换
            i++;
            j--;
        }
    }while(i<=j);
    if(l<j) 
		qsort(l,j);
    if(i<r) 
		qsort(i,r);
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    qsort(1,n);
    for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\n",a[n]);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值