每日总结2022.1.5(求先序排列、并查集)

get到新知识,心情愉悦

先看先序排列

P1030 [NOIP2001 普及组] 求先序排列https://www.luogu.com.cn/problem/P1030

题目描述

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

输入格式

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

输出格式

共一行一个字符串,表示一棵二叉树的先序。

输入输出样例

输入 #1复制

BADC
BDCA

输出 #1复制

ABCD

说明/提示

【题目来源】

NOIP 2001 普及组第三题

思路:在草稿纸上多次手工遍历,找出由中后序排列->先序排列的规律,先从后序最后一个字母(这就是根)开始A,在中序知道对应的字母,将中序分成俩部分,依据中序的俩部分,将后序分成俩部分,左边一部分是A的左子树,右边一部分是A的右子树。以此类推。。。先序为根左右,所以先把根输出,然后递归左半然后右半。

 代码实现:

#include<bits/stdc++.h>
using namespace std;
void DLR(char *m,char *b,int l,int r,int i,int j)
{
	if(i==j)
	{
		printf("%c",b[j]);
		return;
	}
	for(int k=l;k<=r;k++)
	{
		if(m[k]==b[j])
		{
			printf("%c",b[j]);
			if(k-1>=l) DLR(m,b,l,k-1,i,i+(k-1-l));
			if(k+1<=r) DLR(m,b,k+1,r,j+k-r,j-1);
			break;
		}
	}
}
int main()
{
	char m[30];
	char b[30];
	cin>>m>>b;
	int len=strlen(m);
	DLR(m,b,0,len-1,0,len-1);
	return 0;
}
//ABEDFCHG
//AEFDBHGC

新知识:并查集P3367 【模板】并查集https://www.luogu.com.cn/problem/P3367

并查集,合并与查询,是一种树结构。原来判断两个对象之间的关系,有关系和没关系。无法得出具体关系。

通过数组parent[x]=x_father来模拟两个元素之间的结点与孩子的关系,x的结点是x_father。

比如如果要合并1和2所在的集合,就要把1和2所在的那棵树的根找出来(find),然后将一个根接在(connect)另一个根上面,一个为结点,一个为子树。

题目描述

如题,现在有一个并查集,你需要完成合并和查询操作。

输入格式

第一行包含两个整数N,M ,表示共有 N 个元素和 M 个操作。

接下来 MM 行,每行包含三个整数 Zi,Xi,Yi​ 。

当 Zi=1 时,将Xi​ 与Yi​ 所在的集合合并。

当 Zi​=2 时,输出 Xi​ 与Yi​ 是否在同一集合内,是的输出 Y ;否则输出 N 。

输出格式

对于每一个 Zi​=2 的操作,都有一行输出,每行包含一个大写字母,为 Y 或者 N 。

输入输出样例

输入 #1复制

4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4

输出 #1复制

N
Y
N
Y

说明/提示

对于30% 的数据,N≤10,M≤20。

对于 70% 的数据,N≤100,M≤103。

对于 100% 的数据,1≤N≤104,1≤M≤2×105,1≤Xi​,Yi​≤N,Zi​∈{1,2}。

代码实现:

#include<bits/stdc++.h>
using namespace std;

int find_root(int x,int *parent)
{
	int x_root=x;
	while(parent[x_root]!=0)
	{
		x_root=parent[x_root];
	}
	return x_root;
}

int connect(int x,int y,int *parent)
{
	int x_root=find_root(x,parent);
	int y_root=find_root(y,parent);
	if(x_root==y_root)
	{
		return 0;
	}
	else
	{
		parent[x_root]=y_root;
		return 1;
	}
}
int main()
{
	int parent[10000+5]={0};
	int Z,M,N;
	cin>>N>>M;
	int x,y;
	while(M--)
	{
		cin>>Z>>x>>y;
		if(Z==1) connect(x,y,parent);
		else
		{
			if(find_root(x,parent)==find_root(y,parent)&&find_root(x,parent)!=0)
			{
				printf("Y\n");
			}
			else
			{
				printf("N\n");
			}
		}
	}
	return 0;
}

由于这里在合并的时候总是,左边那个集合连上右边那个集合,会导致树的深度过长,在find的时候会花费额外的时间,以至于提交结果时间超限

所以要将深度小的接在深度长的上面,就需要多定义一个数组deep 来存储深度

#include<bits/stdc++.h>
using namespace std;

int find_root(int x,int *parent)
{
	int x_root=x;
	while(parent[x_root]!=0)
	{
		x_root=parent[x_root];
	}
	return x_root;
}

int connect(int x,int y,int *parent,int *deep)
{
	int x_root=find_root(x,parent);
	int y_root=find_root(y,parent);
	if(x_root==y_root)
	{
		return 0;
	}
	else
	{
		if(deep[x_root]>deep[y_root])
		{
			parent[y_root]=x_root;
		}
		else if(deep[y_root]>deep[x_root])
		{
			parent[x_root]=y_root;
		}
		else
		{
			parent[y_root]=x_root;
			deep[x_root]++;
		}
		return 1;
	}
}
int main()
{
	int parent[10000+5]={0};
	int deep[10000+5]={0};
	int Z,M,N;
	cin>>N>>M;
	int x,y;
	while(M--)
	{
		cin>>Z>>x>>y;
		if(Z==1) connect(x,y,parent,deep);
		else
		{
			if(find_root(x,parent)==find_root(y,parent)&&find_root(x,parent)!=0)
			{
				printf("Y\n");
			}
			else
			{
				printf("N\n");
			}
		}
	}
	return 0;
}

AC,不过谁能告诉我这个N有什么用????满脸疑惑

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值